ADDED: Import vector graphics into Symbol editor (SVG, DXF).

This commit is contained in:
Alex Shvartzkop 2023-10-09 03:54:34 +03:00
parent f4f8523c59
commit 60d069757a
25 changed files with 2668 additions and 212 deletions

View File

@ -33,6 +33,7 @@
#include <eda_text.h>
#include <math/vector2d.h>
#include <gal/color4d.h>
#include <stroke_params.h>
#include <list>
#include <memory>
@ -208,22 +209,20 @@ public:
*
* @param aOrigin is the segment origin point expressed in mm.
* @param aEnd is the segment end point expressed in mm.
* @param aWidth is the segment thickness in mm. Use -1 for default line thickness
* @param aColor is the shape color
* @param aStroke is the shape stroke parameters.
*/
virtual void AddLine( const VECTOR2D& aOrigin, const VECTOR2D& aEnd, double aWidth,
const COLOR4D& aColor ) = 0;
virtual void AddLine( const VECTOR2D& aOrigin, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke ) = 0;
/**
* Create an object representing a circle.
*
* @param aCenter is the circle center point expressed in mm.
* @param aRadius is the circle radius expressed in mm.
* @param aWidth is the segment thickness in mm. Use -1 for default line thickness
* @param aColor is the shape color
* @param aStroke is the shape stroke parameters.
*/
virtual void AddCircle( const VECTOR2D& aCenter, double aRadius, double aWidth, bool aFilled,
const COLOR4D& aColor ) = 0;
virtual void AddCircle( const VECTOR2D& aCenter, double aRadius, const STROKE_PARAMS& aStroke,
bool aFilled, const COLOR4D& aFillColor ) = 0;
/**
* Create an object representing an arc.
@ -232,14 +231,21 @@ public:
* @param aStart is the arc arm end point expressed in mm.
* Its length is the arc radius.
* @param aAngle is the arc angle.
* @param aWidth is the segment thickness in mm. Use -1 for default line thickness
* @param aColor is the shape color
* @param aStroke is the shape stroke parameters.
*/
virtual void AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart, const EDA_ANGLE& aAngle,
double aWidth, const COLOR4D& aColor ) = 0;
const STROKE_PARAMS& aStroke ) = 0;
virtual void AddPolygon( const std::vector<VECTOR2D>& aVertices, double aWidth,
const COLOR4D& aColor ) = 0;
/**
* Create an object representing a polygon.
*
* @param aVertices is the array of vertices.
* @param aWidth is the stroke width.
* @param aStroke is the shape stroke parameters.
* @param aFillColor is the fill color.
*/
virtual void AddPolygon( const std::vector<VECTOR2D>& aVertices, const STROKE_PARAMS& aStroke,
bool aFilled, const COLOR4D& aFillColor ) = 0;
/**
* Create an object representing a text.
@ -266,12 +272,11 @@ public:
* @param aBezierControl1 is the first Bezier control point expressed in mm.
* @param aBezierControl2 is the second Bezier control point expressed in mm.
* @param aEnd is the curve end point expressed in mm.
* @param aWidth is the segment thickness in mm. Use -1 for default line thickness
* @param aColor is the shape color
* @param aStroke is the shape stroke parameters.
*/
virtual void AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd, double aWidth,
const COLOR4D& aColor ) = 0;
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke ) = 0;
protected:
///< Add an item to the imported shapes list.

View File

@ -38,32 +38,35 @@ static std::unique_ptr<T> make_shape( const Args&... aArguments )
return std::make_unique<T>( aArguments... );
}
void GRAPHICS_IMPORTER_BUFFER::AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd, double aWidth,
const COLOR4D& aColor )
void GRAPHICS_IMPORTER_BUFFER::AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke )
{
m_shapes.push_back( make_shape< IMPORTED_LINE >( aStart, aEnd, aWidth, aColor ) );
m_shapes.push_back( make_shape<IMPORTED_LINE>( aStart, aEnd, aStroke ) );
}
void GRAPHICS_IMPORTER_BUFFER::AddCircle( const VECTOR2D& aCenter, double aRadius, double aWidth,
bool aFilled, const COLOR4D& aColor )
void GRAPHICS_IMPORTER_BUFFER::AddCircle( const VECTOR2D& aCenter, double aRadius,
const STROKE_PARAMS& aStroke, bool aFilled,
const COLOR4D& aFillColor )
{
m_shapes.push_back( make_shape<IMPORTED_CIRCLE>( aCenter, aRadius, aWidth, aFilled, aColor ) );
m_shapes.push_back(
make_shape<IMPORTED_CIRCLE>( aCenter, aRadius, aStroke, aFilled, aFillColor ) );
}
void GRAPHICS_IMPORTER_BUFFER::AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart,
const EDA_ANGLE& aAngle, double aWidth,
const COLOR4D& aColor )
const EDA_ANGLE& aAngle, const STROKE_PARAMS& aStroke )
{
m_shapes.push_back( make_shape<IMPORTED_ARC>( aCenter, aStart, aAngle, aWidth, aColor ) );
m_shapes.push_back( make_shape<IMPORTED_ARC>( aCenter, aStart, aAngle, aStroke ) );
}
void GRAPHICS_IMPORTER_BUFFER::AddPolygon( const std::vector<VECTOR2D>& aVertices, double aWidth,
const COLOR4D& aColor )
void GRAPHICS_IMPORTER_BUFFER::AddPolygon( const std::vector<VECTOR2D>& aVertices,
const STROKE_PARAMS& aStroke, bool aFilled,
const COLOR4D& aFillColor )
{
m_shapes.push_back( make_shape<IMPORTED_POLYGON>( aVertices, aWidth, aColor ) );
m_shapes.push_back( make_shape<IMPORTED_POLYGON>( aVertices, aStroke, aFilled, aFillColor ) );
m_shapes.back()->SetParentShapeIndex( m_shapeFillRules.size() - 1 );
}
@ -73,16 +76,17 @@ void GRAPHICS_IMPORTER_BUFFER::AddText( const VECTOR2D& aOrigin, const wxString&
double aOrientation, GR_TEXT_H_ALIGN_T aHJustify,
GR_TEXT_V_ALIGN_T aVJustify, const COLOR4D& aColor )
{
m_shapes.push_back( make_shape< IMPORTED_TEXT >( aOrigin, aText, aHeight, aWidth,
aThickness, aOrientation, aHJustify, aVJustify, aColor ) );
m_shapes.push_back( make_shape<IMPORTED_TEXT>( aOrigin, aText, aHeight, aWidth, aThickness,
aOrientation, aHJustify, aVJustify, aColor ) );
}
void GRAPHICS_IMPORTER_BUFFER::AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
double aWidth, const COLOR4D& aColor )
const STROKE_PARAMS& aStroke )
{
m_shapes.push_back( make_shape<IMPORTED_SPLINE>( aStart, aBezierControl1, aBezierControl2, aEnd, aWidth, aColor ) );
m_shapes.push_back( make_shape<IMPORTED_SPLINE>( aStart, aBezierControl1, aBezierControl2, aEnd,
aStroke ) );
}
@ -101,8 +105,8 @@ void GRAPHICS_IMPORTER_BUFFER::ImportTo( GRAPHICS_IMPORTER& aImporter )
// converts a single SVG-style polygon (multiple outlines, hole detection based on orientation, custom fill rule) to a format that can be digested by KiCad (single outline, fractured)
static void convertPolygon( std::list<std::unique_ptr<IMPORTED_SHAPE>>& aShapes,
std::vector<IMPORTED_POLYGON*>& aPaths,
GRAPHICS_IMPORTER::POLY_FILL_RULE aFillRule, double aWidth,
const COLOR4D& aColor )
GRAPHICS_IMPORTER::POLY_FILL_RULE aFillRule,
const STROKE_PARAMS& aStroke, bool aFilled, const COLOR4D& aFillColor )
{
double minX = std::numeric_limits<double>::max();
double minY = minX;
@ -170,16 +174,18 @@ static void convertPolygon( std::list<std::unique_ptr<IMPORTED_SHAPE>>& aShapes,
pts.emplace_back( VECTOR2D( xp, yp ) );
}
aShapes.push_back( std::make_unique<IMPORTED_POLYGON>( pts, aWidth, aColor ) );
aShapes.push_back(
std::make_unique<IMPORTED_POLYGON>( pts, aStroke, aFilled, aFillColor ) );
}
}
void GRAPHICS_IMPORTER_BUFFER::PostprocessNestedPolygons()
{
int curShapeIdx = -1;
double lastWidth = 0;
COLOR4D lastColor = COLOR4D::UNSPECIFIED;
int curShapeIdx = -1;
STROKE_PARAMS lastStroke;
bool lastFilled = false;
COLOR4D lastFillColor = COLOR4D::UNSPECIFIED;
std::list<std::unique_ptr<IMPORTED_SHAPE>> newShapes;
std::vector<IMPORTED_POLYGON*> polypaths;
@ -198,19 +204,24 @@ void GRAPHICS_IMPORTER_BUFFER::PostprocessNestedPolygons()
if( index != curShapeIdx && curShapeIdx >= 0 )
{
convertPolygon( newShapes, polypaths, m_shapeFillRules[curShapeIdx], lastWidth,
lastColor );
convertPolygon( newShapes, polypaths, m_shapeFillRules[curShapeIdx], lastStroke,
lastFilled, lastFillColor );
polypaths.clear();
}
curShapeIdx = index;
lastWidth = poly->GetWidth();
lastColor = poly->GetColor();
lastStroke = poly->GetStroke();
lastFilled = poly->isFilled();
lastFillColor = poly->GetFillColor();
polypaths.push_back( poly );
}
if( curShapeIdx >= 0 )
convertPolygon( newShapes, polypaths, m_shapeFillRules[curShapeIdx], lastWidth, lastColor );
{
convertPolygon( newShapes, polypaths, m_shapeFillRules[curShapeIdx], lastStroke, lastFilled,
lastFillColor );
}
m_shapes.swap( newShapes );
}

View File

@ -53,16 +53,14 @@ protected:
class IMPORTED_LINE : public IMPORTED_SHAPE
{
public:
IMPORTED_LINE( const VECTOR2D& aStart, const VECTOR2D& aEnd, double aWidth,
const COLOR4D& aColor ) :
m_start( aStart ),
m_end( aEnd ), m_width( aWidth ), m_color( aColor )
IMPORTED_LINE( const VECTOR2D& aStart, const VECTOR2D& aEnd, const STROKE_PARAMS& aStroke ) :
m_start( aStart ), m_end( aEnd ), m_stroke( aStroke )
{
}
void ImportTo( GRAPHICS_IMPORTER& aImporter ) const override
{
aImporter.AddLine( m_start, m_end, m_width, m_color );
aImporter.AddLine( m_start, m_end, m_stroke );
}
virtual std::unique_ptr<IMPORTED_SHAPE> clone() const override
@ -70,33 +68,32 @@ public:
return std::make_unique<IMPORTED_LINE>( *this );
}
void Transform(const MATRIX3x3D& aTransform, const VECTOR2D& aTranslation) override
void Transform( const MATRIX3x3D& aTransform, const VECTOR2D& aTranslation ) override
{
m_start = aTransform * m_start + aTranslation;
m_end = aTransform * m_end + aTranslation;
}
private:
VECTOR2D m_start;
VECTOR2D m_end;
double m_width;
COLOR4D m_color;
VECTOR2D m_start;
VECTOR2D m_end;
STROKE_PARAMS m_stroke;
};
class IMPORTED_CIRCLE : public IMPORTED_SHAPE
{
public:
IMPORTED_CIRCLE( const VECTOR2D& aCenter, double aRadius, double aWidth, bool aFilled,
const COLOR4D& aColor ) :
IMPORTED_CIRCLE( const VECTOR2D& aCenter, double aRadius, const STROKE_PARAMS& aStroke,
bool aFilled, const COLOR4D& aFillColor ) :
m_center( aCenter ),
m_radius( aRadius ), m_width( aWidth ), m_filled( aFilled ), m_color( aColor )
m_radius( aRadius ), m_stroke( aStroke ), m_filled( aFilled ), m_fillColor( aFillColor )
{
}
void ImportTo( GRAPHICS_IMPORTER& aImporter ) const override
{
aImporter.AddCircle( m_center, m_radius, m_width, m_filled, m_color );
aImporter.AddCircle( m_center, m_radius, m_stroke, m_filled, m_fillColor );
}
virtual std::unique_ptr<IMPORTED_SHAPE> clone() const override
@ -116,11 +113,11 @@ public:
}
private:
VECTOR2D m_center;
double m_radius;
double m_width;
bool m_filled;
COLOR4D m_color;
VECTOR2D m_center;
double m_radius;
STROKE_PARAMS m_stroke;
bool m_filled;
COLOR4D m_fillColor;
};
@ -128,15 +125,15 @@ class IMPORTED_ARC : public IMPORTED_SHAPE
{
public:
IMPORTED_ARC( const VECTOR2D& aCenter, const VECTOR2D& aStart, const EDA_ANGLE& aAngle,
double aWidth, const COLOR4D& aColor ) :
const STROKE_PARAMS& aStroke ) :
m_center( aCenter ),
m_start( aStart ), m_angle( aAngle ), m_width( aWidth ), m_color( aColor )
m_start( aStart ), m_angle( aAngle ), m_stroke( aStroke )
{
}
void ImportTo( GRAPHICS_IMPORTER& aImporter ) const override
{
aImporter.AddArc( m_center, m_start, m_angle, m_width, m_color );
aImporter.AddArc( m_center, m_start, m_angle, m_stroke );
}
virtual std::unique_ptr<IMPORTED_SHAPE> clone() const override
@ -151,27 +148,26 @@ public:
}
private:
VECTOR2D m_center;
VECTOR2D m_start;
EDA_ANGLE m_angle;
double m_width;
COLOR4D m_color;
VECTOR2D m_center;
VECTOR2D m_start;
EDA_ANGLE m_angle;
STROKE_PARAMS m_stroke;
};
class IMPORTED_POLYGON : public IMPORTED_SHAPE
{
public:
IMPORTED_POLYGON( const std::vector<VECTOR2D>& aVertices, double aWidth,
const COLOR4D& aColor ) :
IMPORTED_POLYGON( const std::vector<VECTOR2D>& aVertices, const STROKE_PARAMS& aStroke,
bool aFilled, const COLOR4D& aFillColor ) :
m_vertices( aVertices ),
m_width( aWidth ), m_color( aColor )
m_stroke( aStroke ), m_filled( aFilled ), m_fillColor( aFillColor )
{
}
void ImportTo( GRAPHICS_IMPORTER& aImporter ) const override
{
aImporter.AddPolygon( m_vertices, m_width, m_color );
aImporter.AddPolygon( m_vertices, m_stroke, m_filled, m_fillColor );
}
virtual std::unique_ptr<IMPORTED_SHAPE> clone() const override
@ -181,7 +177,7 @@ public:
void Transform( const MATRIX3x3D& aTransform, const VECTOR2D& aTranslation ) override
{
for(VECTOR2D& vert : m_vertices )
for( VECTOR2D& vert : m_vertices )
{
vert = aTransform * vert + aTranslation;
}
@ -189,14 +185,17 @@ public:
std::vector<VECTOR2D>& Vertices() { return m_vertices; }
double GetWidth() const { return m_width; }
bool isFilled() const { return m_filled; }
const COLOR4D& GetColor() const { return m_color; }
const COLOR4D& GetFillColor() const { return m_fillColor; }
const STROKE_PARAMS& GetStroke() const { return m_stroke; }
private:
std::vector<VECTOR2D> m_vertices;
double m_width;
COLOR4D m_color;
STROKE_PARAMS m_stroke;
bool m_filled;
COLOR4D m_fillColor;
};
@ -246,17 +245,17 @@ class IMPORTED_SPLINE : public IMPORTED_SHAPE
{
public:
IMPORTED_SPLINE( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd, double aWidth,
const COLOR4D& aColor ) :
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke ) :
m_start( aStart ),
m_bezierControl1( aBezierControl1 ), m_bezierControl2( aBezierControl2 ), m_end( aEnd ),
m_width( aWidth ), m_color( aColor )
m_stroke( aStroke )
{
}
void ImportTo( GRAPHICS_IMPORTER& aImporter ) const override
{
aImporter.AddSpline( m_start, m_bezierControl1, m_bezierControl2, m_end, m_width, m_color );
aImporter.AddSpline( m_start, m_bezierControl1, m_bezierControl2, m_end, m_stroke );
}
virtual std::unique_ptr<IMPORTED_SHAPE> clone() const override
@ -273,38 +272,37 @@ public:
}
private:
VECTOR2D m_start;
VECTOR2D m_bezierControl1;
VECTOR2D m_bezierControl2;
VECTOR2D m_end;
double m_width;
COLOR4D m_color;
VECTOR2D m_start;
VECTOR2D m_bezierControl1;
VECTOR2D m_bezierControl2;
VECTOR2D m_end;
STROKE_PARAMS m_stroke;
};
class GRAPHICS_IMPORTER_BUFFER : public GRAPHICS_IMPORTER
{
public:
void AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd, double aWidth,
const COLOR4D& aColor = COLOR4D::UNSPECIFIED ) override;
void AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke ) override;
void AddCircle( const VECTOR2D& aCenter, double aRadius, double aWidth, bool aFilled,
const COLOR4D& aColor = COLOR4D::UNSPECIFIED ) override;
void AddCircle( const VECTOR2D& aCenter, double aRadius, const STROKE_PARAMS& aStroke,
bool aFilled, const COLOR4D& aFillColor = COLOR4D::UNSPECIFIED ) override;
void AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart, const EDA_ANGLE& aAngle,
double aWidth, const COLOR4D& aColor = COLOR4D::UNSPECIFIED ) override;
const STROKE_PARAMS& aStroke ) override;
void AddPolygon( const std::vector<VECTOR2D>& aVertices, double aWidth,
const COLOR4D& aColor = COLOR4D::UNSPECIFIED ) override;
void AddPolygon( const std::vector<VECTOR2D>& aVertices, const STROKE_PARAMS& aStroke,
bool aFilled, const COLOR4D& aFillColor = COLOR4D::UNSPECIFIED ) override;
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,
const COLOR4D& aColor = COLOR4D::UNSPECIFIED ) override;
void AddSpline( const VECTOR2D& aStart, const VECTOR2D& BezierControl1,
const VECTOR2D& BezierControl2, const VECTOR2D& aEnd, double aWidth,
const COLOR4D& aColor = COLOR4D::UNSPECIFIED ) override;
void AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke ) override;
void ImportTo( GRAPHICS_IMPORTER& aImporter );
void AddShape( std::unique_ptr<IMPORTED_SHAPE>& aShape );

View File

@ -113,21 +113,69 @@ bool SVG_IMPORT_PLUGIN::Import()
double lineWidth = shape->stroke.type != NSVG_PAINT_NONE ? shape->strokeWidth : -1;
bool filled = shape->fill.type != NSVG_PAINT_NONE && alpha( shape->fill.color ) > 0;
COLOR4D color = COLOR4D::UNSPECIFIED;
COLOR4D fillColor = COLOR4D::UNSPECIFIED;
if( shape->fill.type == NSVG_PAINT_COLOR )
{
unsigned int icolor = shape->fill.color;
color.r = std::clamp( ( icolor >> 0 ) & 0xFF, 0u, 255u ) / 255.0;
color.g = std::clamp( ( icolor >> 8 ) & 0xFF, 0u, 255u ) / 255.0;
color.b = std::clamp( ( icolor >> 16 ) & 0xFF, 0u, 255u ) / 255.0;
color.a = std::clamp( ( icolor >> 24 ) & 0xFF, 0u, 255u ) / 255.0;
fillColor.r = std::clamp( ( icolor >> 0 ) & 0xFF, 0u, 255u ) / 255.0;
fillColor.g = std::clamp( ( icolor >> 8 ) & 0xFF, 0u, 255u ) / 255.0;
fillColor.b = std::clamp( ( icolor >> 16 ) & 0xFF, 0u, 255u ) / 255.0;
fillColor.a = std::clamp( ( icolor >> 24 ) & 0xFF, 0u, 255u ) / 255.0;
if( color == COLOR4D::BLACK ) // nanosvg probably didn't read it properly, use default
color = COLOR4D::UNSPECIFIED;
// nanosvg probably didn't read it properly, use default
if( fillColor == COLOR4D::BLACK )
fillColor = COLOR4D::UNSPECIFIED;
}
COLOR4D strokeColor = COLOR4D::UNSPECIFIED;
if( shape->stroke.type == NSVG_PAINT_COLOR )
{
unsigned int icolor = shape->stroke.color;
strokeColor.r = std::clamp( ( icolor >> 0 ) & 0xFF, 0u, 255u ) / 255.0;
strokeColor.g = std::clamp( ( icolor >> 8 ) & 0xFF, 0u, 255u ) / 255.0;
strokeColor.b = std::clamp( ( icolor >> 16 ) & 0xFF, 0u, 255u ) / 255.0;
strokeColor.a = std::clamp( ( icolor >> 24 ) & 0xFF, 0u, 255u ) / 255.0;
// nanosvg probably didn't read it properly, use default
if( strokeColor == COLOR4D::BLACK )
strokeColor = COLOR4D::UNSPECIFIED;
}
PLOT_DASH_TYPE dashType = PLOT_DASH_TYPE::SOLID;
if( shape->strokeDashCount > 0 )
{
float* dashArray = shape->strokeDashArray;
int dotCount = 0;
int dashCount = 0;
const float dashThreshold = shape->strokeWidth * 1.9f;
for( int i = 0; i < shape->strokeDashCount; i += 2 )
{
if( dashArray[i] < dashThreshold )
dotCount++;
else
dashCount++;
}
if( dotCount > 0 && dashCount == 0 )
dashType = PLOT_DASH_TYPE::DOT;
else if( dotCount == 0 && dashCount > 0 )
dashType = PLOT_DASH_TYPE::DASH;
else if( dotCount == 1 && dashCount == 1 )
dashType = PLOT_DASH_TYPE::DASHDOT;
else if( dotCount == 2 && dashCount == 1 )
dashType = PLOT_DASH_TYPE::DASHDOTDOT;
}
STROKE_PARAMS stroke( lineWidth, dashType, strokeColor );
GRAPHICS_IMPORTER::POLY_FILL_RULE rule = GRAPHICS_IMPORTER::PF_NONZERO;
switch( shape->fillRule )
@ -143,7 +191,7 @@ bool SVG_IMPORT_PLUGIN::Import()
{
bool closed = path->closed || filled || rule == GRAPHICS_IMPORTER::PF_EVEN_ODD;
DrawPath( path->pts, path->npts, closed, filled, lineWidth, color );
DrawPath( path->pts, path->npts, closed, stroke, filled, fillColor );
}
}
@ -204,18 +252,19 @@ BOX2D SVG_IMPORT_PLUGIN::GetImageBBox() const
}
void SVG_IMPORT_PLUGIN::DrawPath( const float* aPoints, int aNumPoints, bool aPoly, bool aFilled,
double aLineWidth, const COLOR4D& aColor )
void SVG_IMPORT_PLUGIN::DrawPath( const float* aPoints, int aNumPoints, bool aClosedPath,
const STROKE_PARAMS& aStroke, bool aFilled,
const COLOR4D& aFillColor )
{
std::vector< VECTOR2D > collectedPathPoints;
std::vector<VECTOR2D> collectedPathPoints;
if( aNumPoints > 0 )
DrawCubicBezierPath( aPoints, aNumPoints, collectedPathPoints );
if( aPoly && aFilled )
DrawPolygon( collectedPathPoints, aLineWidth, aColor );
if( aClosedPath )
DrawPolygon( collectedPathPoints, aStroke, aFilled, aFillColor );
else
DrawLineSegments( collectedPathPoints, aLineWidth, aColor );
DrawLineSegments( collectedPathPoints, aStroke );
}
@ -250,20 +299,21 @@ void SVG_IMPORT_PLUGIN::DrawCubicBezierCurve( const float* aPoints,
}
void SVG_IMPORT_PLUGIN::DrawPolygon( const std::vector<VECTOR2D>& aPoints, double aWidth,
const COLOR4D& aColor )
void SVG_IMPORT_PLUGIN::DrawPolygon( const std::vector<VECTOR2D>& aPoints,
const STROKE_PARAMS& aStroke, bool aFilled,
const COLOR4D& aFillColor )
{
m_internalImporter.AddPolygon( aPoints, aWidth, aColor );
m_internalImporter.AddPolygon( aPoints, aStroke, aFilled, aFillColor );
}
void SVG_IMPORT_PLUGIN::DrawLineSegments( const std::vector<VECTOR2D>& aPoints, double aWidth,
const COLOR4D& aColor )
void SVG_IMPORT_PLUGIN::DrawLineSegments( const std::vector<VECTOR2D>& aPoints,
const STROKE_PARAMS& aStroke )
{
unsigned int numLineStartPoints = aPoints.size() - 1;
for( unsigned int pointIndex = 0; pointIndex < numLineStartPoints; ++pointIndex )
m_internalImporter.AddLine( aPoints[ pointIndex ], aPoints[ pointIndex + 1 ], aWidth, aColor );
m_internalImporter.AddLine( aPoints[pointIndex], aPoints[pointIndex + 1], aStroke );
}

View File

@ -31,6 +31,7 @@
#include <wildcards_and_files_ext.h>
#include <vector>
#include <stroke_params.h>
class SVG_IMPORT_PLUGIN : public GRAPHICS_IMPORT_PLUGIN
@ -70,18 +71,18 @@ public:
virtual BOX2D GetImageBBox() const override;
private:
void DrawPath( const float* aPoints, int aNumPoints, bool aClosedPath, bool aFilled,
double aLineWidth, const COLOR4D& aColor );
void DrawPath( const float* aPoints, int aNumPoints, bool aClosedPath,
const STROKE_PARAMS& aStroke, bool aFilled, const COLOR4D& aFillColor );
void DrawCubicBezierPath( const float* aPoints, int aNumPoints,
std::vector<VECTOR2D>& aGeneratedPoints );
void DrawCubicBezierCurve( const float* aPoints, std::vector<VECTOR2D>& aGeneratedPoints );
void DrawPolygon( const std::vector<VECTOR2D>& aPoints, double aWidth, const COLOR4D& aColor );
void DrawPolygon( const std::vector<VECTOR2D>& aPoints, const STROKE_PARAMS& aStroke,
bool aFilled, const COLOR4D& aFillColor );
void DrawLineSegments( const std::vector<VECTOR2D>& aPoints, double aWidth,
const COLOR4D& aColor );
void DrawLineSegments( const std::vector<VECTOR2D>& aPoints, const STROKE_PARAMS& aStroke );
struct NSVGimage* m_parsedImage;

View File

@ -282,6 +282,8 @@ set ( EESCHEMA_LIBEDIT_SRCS
)
set( EESCHEMA_IMPORT_GFX
import_gfx/dialog_import_gfx_sch_base.cpp
import_gfx/dialog_import_gfx_sch.cpp
import_gfx/graphics_importer_lib_symbol.cpp
)

View File

@ -121,6 +121,7 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
m_NetlistPanel(),
m_PlotPanel(),
m_SymChooserPanel(),
m_ImportGraphics(),
m_Selection(),
m_Simulator(),
m_RescueNeverShow( false )
@ -551,6 +552,27 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
m_params.emplace_back( new PARAM<bool>( "symbol_chooser.place_all_units",
&m_SymChooserPanel.place_all_units, true ) );
m_params.emplace_back( new PARAM<bool>( "import_graphics.interactive_placement",
&m_ImportGraphics.interactive_placement, true ) );
m_params.emplace_back( new PARAM<int>( "import_graphics.line_width_units",
&m_ImportGraphics.dxf_line_width_units, 0 ) );
m_params.emplace_back( new PARAM<double>( "import_graphics.line_width",
&m_ImportGraphics.dxf_line_width, 0.2 ) );
m_params.emplace_back( new PARAM<int>( "import_graphics.origin_units",
&m_ImportGraphics.origin_units, 0 ) );
m_params.emplace_back( new PARAM<double>( "import_graphics.origin_x",
&m_ImportGraphics.origin_x, 0 ) );
m_params.emplace_back( new PARAM<double>( "import_graphics.origin_y",
&m_ImportGraphics.origin_y, 0 ) );
m_params.emplace_back( new PARAM<int>( "import_graphics.dxf_units",
&m_ImportGraphics.dxf_units, 0 ) );
m_params.emplace_back( new PARAM<bool>( "system.never_show_rescue_dialog",
&m_RescueNeverShow, false ) );

View File

@ -262,6 +262,18 @@ public:
bool place_all_units;
};
struct DIALOG_IMPORT_GRAPHICS
{
bool interactive_placement;
wxString last_file;
double dxf_line_width;
int dxf_line_width_units;
int origin_units;
double origin_x;
double origin_y;
int dxf_units;
};
struct SIMULATOR
{
int plot_panel_width;
@ -334,6 +346,8 @@ public:
PANEL_SYM_CHOOSER m_SymChooserPanel;
DIALOG_IMPORT_GRAPHICS m_ImportGraphics;
SELECTION m_Selection;
SIMULATOR m_Simulator;

View File

@ -0,0 +1,311 @@
/*
* 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-2023 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
*/
#include "dialog_import_gfx_sch.h"
#include <map>
#include <import_gfx/graphics_importer_lib_symbol.h>
#include <import_gfx/dxf_import_plugin.h>
#include <base_units.h>
#include <kiface_base.h>
#include <locale_io.h>
#include <bitmaps.h>
#include <wildcards_and_files_ext.h>
#include <eeschema_settings.h>
#include <sch_edit_frame.h>
#include <symbol_editor_settings.h>
#include <symbol_edit_frame.h>
#include <wx/filedlg.h>
#include <wx/msgdlg.h>
#include <dialogs/html_message_box.h>
#include <widgets/std_bitmap_button.h>
#include <memory>
// Static members of DIALOG_IMPORT_GFX_SCH, to remember the user's choices during the session
bool DIALOG_IMPORT_GFX_SCH::m_placementInteractive = true;
double DIALOG_IMPORT_GFX_SCH::m_importScale = 1.0; // Do not change the imported items size
const std::map<DXF_IMPORT_UNITS, wxString> dxfUnitsMap = {
{ DXF_IMPORT_UNITS::INCHES, _( "Inches" ) },
{ DXF_IMPORT_UNITS::MILLIMETERS, _( "Millimeters" ) },
{ DXF_IMPORT_UNITS::MILS, _( "Mils" ) },
{ DXF_IMPORT_UNITS::CENTIMETERS, _( "Centimeter" ) },
{ DXF_IMPORT_UNITS::FEET, _( "Feet" ) },
};
DIALOG_IMPORT_GFX_SCH::DIALOG_IMPORT_GFX_SCH( SCH_BASE_FRAME* aParent ) :
DIALOG_IMPORT_GFX_SCH_BASE( aParent ),
m_parent( aParent ),
m_xOrigin( aParent, m_xLabel, m_xCtrl, m_xUnits ),
m_yOrigin( aParent, m_yLabel, m_yCtrl, m_yUnits ),
m_defaultLineWidth( aParent, m_lineWidthLabel, m_lineWidthCtrl, m_lineWidthUnits )
{
auto initWidgetsFromSettings = [&]( const auto& aCfg )
{
m_placementInteractive = aCfg->m_ImportGraphics.interactive_placement;
m_xOrigin.SetValue( aCfg->m_ImportGraphics.origin_x * schIUScale.IU_PER_MM );
m_yOrigin.SetValue( aCfg->m_ImportGraphics.origin_y * schIUScale.IU_PER_MM );
m_defaultLineWidth.SetValue( aCfg->m_ImportGraphics.dxf_line_width * schIUScale.IU_PER_MM );
m_textCtrlFileName->SetValue( aCfg->m_ImportGraphics.last_file );
m_rbInteractivePlacement->SetValue( m_placementInteractive );
m_rbAbsolutePlacement->SetValue( !m_placementInteractive );
m_importScaleCtrl->SetValue( wxString::Format( wxT( "%f" ), m_importScale ) );
for( const std::pair<const DXF_IMPORT_UNITS, wxString>& unitEntry : dxfUnitsMap )
m_choiceDxfUnits->Append( unitEntry.second );
m_choiceDxfUnits->SetSelection( aCfg->m_ImportGraphics.dxf_units );
m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
};
if( SYMBOL_EDIT_FRAME* symFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( aParent ) )
{
m_importer = std::make_unique<GRAPHICS_IMPORTER_LIB_SYMBOL>( symFrame->GetCurSymbol(),
symFrame->GetUnit() );
SYMBOL_EDITOR_SETTINGS* cfg = m_parent->libeditconfig();
initWidgetsFromSettings( cfg );
}
else if( SCH_EDIT_FRAME* schFrame = dynamic_cast<SCH_EDIT_FRAME*>( aParent ) )
{
/*m_importer = std::make_unique<GRAPHICS_IMPORTER_SCH>( symFrame );
EESCHEMA_SETTINGS* cfg = m_parent->eeconfig();
initWidgetsFromSettings( cfg );*/
}
// construct an import manager with options from config
{
GRAPHICS_IMPORT_MGR::TYPE_LIST blacklist;
// Currently: all types are allowed, so the blacklist is empty
// (no GFX_FILE_T in the blacklist)
// To disable SVG import, enable these 2 lines
// if( !ADVANCED_CFG::GetCfg().m_enableSvgImport )
// blacklist.push_back( GRAPHICS_IMPORT_MGR::SVG );
// The SVG import has currently a flaw: all SVG shapes are imported as curves and
// converted to a lot of segments. A better approach is to convert to polylines
// (not yet existing in Pcbnew) and keep arcs and circles as primitives (not yet
// possible with tinysvg library).
m_gfxImportMgr = std::make_unique<GRAPHICS_IMPORT_MGR>( blacklist );
}
wxCommandEvent dummy;
onFilename( dummy );
SetInitialFocus( m_textCtrlFileName );
SetupStandardButtons();
GetSizer()->Fit( this );
GetSizer()->SetSizeHints( this );
Centre();
m_textCtrlFileName->Connect( wxEVT_COMMAND_TEXT_UPDATED,
wxCommandEventHandler( DIALOG_IMPORT_GFX_SCH::onFilename ),
nullptr, this );
}
DIALOG_IMPORT_GFX_SCH::~DIALOG_IMPORT_GFX_SCH()
{
auto saveToSettings = [&]( const auto& aCfg )
{
aCfg->m_ImportGraphics.interactive_placement = m_placementInteractive;
aCfg->m_ImportGraphics.last_file = m_textCtrlFileName->GetValue();
aCfg->m_ImportGraphics.dxf_line_width = schIUScale.IUTomm( m_defaultLineWidth.GetValue() );
aCfg->m_ImportGraphics.origin_x = schIUScale.IUTomm( m_xOrigin.GetValue() );
aCfg->m_ImportGraphics.origin_y = schIUScale.IUTomm( m_yOrigin.GetValue() );
aCfg->m_ImportGraphics.dxf_units = m_choiceDxfUnits->GetSelection();
m_importScale = EDA_UNIT_UTILS::UI::DoubleValueFromString( m_importScaleCtrl->GetValue() );
};
if( SYMBOL_EDIT_FRAME* symFrame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_parent ) )
{
m_importer = std::make_unique<GRAPHICS_IMPORTER_LIB_SYMBOL>( symFrame->GetCurSymbol(),
symFrame->GetUnit() );
SYMBOL_EDITOR_SETTINGS* cfg = m_parent->libeditconfig();
saveToSettings( cfg );
}
else if( SCH_EDIT_FRAME* schFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_parent ) )
{
/*m_importer = std::make_unique<GRAPHICS_IMPORTER_SCH>( symFrame );
EESCHEMA_SETTINGS* cfg = m_parent->eeconfig();
saveToSettings( cfg );*/
}
m_textCtrlFileName->Disconnect( wxEVT_COMMAND_TEXT_UPDATED,
wxCommandEventHandler( DIALOG_IMPORT_GFX_SCH::onFilename ),
nullptr, this );
}
void DIALOG_IMPORT_GFX_SCH::onFilename( wxCommandEvent& event )
{
bool enableDXFControls = true;
wxString ext = wxFileName( m_textCtrlFileName->GetValue() ).GetExt();
if( std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPluginByExt( ext ) )
enableDXFControls = dynamic_cast<DXF_IMPORT_PLUGIN*>( plugin.get() ) != nullptr;
m_defaultLineWidth.Enable( enableDXFControls );
m_staticTextLineWidth1->Enable( enableDXFControls );
m_choiceDxfUnits->Enable( enableDXFControls );
}
void DIALOG_IMPORT_GFX_SCH::onBrowseFiles( wxCommandEvent& event )
{
wxString path;
wxString filename = m_textCtrlFileName->GetValue();
if( !filename.IsEmpty() )
{
wxFileName fn( filename );
path = fn.GetPath();
filename = fn.GetFullName();
}
// Generate the list of handled file formats
wxString wildcardsDesc;
wxString allWildcards;
for( GRAPHICS_IMPORT_MGR::GFX_FILE_T pluginType : m_gfxImportMgr->GetImportableFileTypes() )
{
std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPlugin( pluginType );
const std::vector<std::string> extensions = plugin->GetFileExtensions();
wildcardsDesc += wxT( "|" ) + plugin->GetName() + AddFileExtListToFilter( extensions );
allWildcards += plugin->GetWildcards() + wxT( ";" );
}
wildcardsDesc = _( "All supported formats" ) + wxT( "|" ) + allWildcards + wildcardsDesc;
wxFileDialog dlg( m_parent, _( "Open File" ), path, filename, wildcardsDesc,
wxFD_OPEN | wxFD_FILE_MUST_EXIST );
if( dlg.ShowModal() == wxID_OK && !dlg.GetPath().IsEmpty() )
m_textCtrlFileName->SetValue( dlg.GetPath() );
}
bool DIALOG_IMPORT_GFX_SCH::TransferDataFromWindow()
{
if( !wxDialog::TransferDataFromWindow() )
return false;
if( m_textCtrlFileName->GetValue().IsEmpty() )
{
wxMessageBox( _( "No file selected!" ) );
return false;
}
wxString ext = wxFileName( m_textCtrlFileName->GetValue() ).GetExt();
double scale = EDA_UNIT_UTILS::UI::DoubleValueFromString( m_importScaleCtrl->GetValue() );
double xscale = scale;
double yscale = scale;
if( dynamic_cast<SYMBOL_EDIT_FRAME*>( m_parent ) )
yscale *= -1;
VECTOR2D origin( m_xOrigin.GetValue() / xscale, m_yOrigin.GetValue() / yscale );
if( std::unique_ptr<GRAPHICS_IMPORT_PLUGIN> plugin = m_gfxImportMgr->GetPluginByExt( ext ) )
{
if( DXF_IMPORT_PLUGIN* dxfPlugin = dynamic_cast<DXF_IMPORT_PLUGIN*>( plugin.get() ) )
{
auto it = dxfUnitsMap.begin();
std::advance( it, m_choiceDxfUnits->GetSelection() );
if( it == dxfUnitsMap.end() )
dxfPlugin->SetUnit( DXF_IMPORT_UNITS::DEFAULT );
else
dxfPlugin->SetUnit( it->first );
m_importer->SetLineWidthMM( schIUScale.IUTomm( m_defaultLineWidth.GetValue() ) );
}
else
{
m_importer->SetLineWidthMM( 0.0 );
}
m_importer->SetPlugin( std::move( plugin ) );
m_importer->SetImportOffsetMM( { schIUScale.IUTomm( origin.x ), schIUScale.IUTomm( origin.y ) } );
LOCALE_IO dummy; // Ensure floats can be read.
if( m_importer->Load( m_textCtrlFileName->GetValue() ) )
m_importer->Import( VECTOR2D( xscale, yscale ) );
// Get warning messages:
wxString warnings = m_importer->GetMessages();
// This isn't a fatal error so allow the dialog to close with wxID_OK.
if( !warnings.empty() )
{
HTML_MESSAGE_BOX dlg( this, _( "Warning" ) );
dlg.MessageSet( _( "Items in the imported file could not be handled properly." ) );
warnings.Replace( wxT( "\n" ), wxT( "<br/>" ) );
dlg.AddHTML_Text( warnings );
dlg.ShowModal();
}
return true;
}
else
{
wxMessageBox( _( "There is no plugin to handle this file type." ) );
return false;
}
}
void DIALOG_IMPORT_GFX_SCH::originOptionOnUpdateUI( wxUpdateUIEvent& event )
{
if( m_rbInteractivePlacement->GetValue() != m_placementInteractive )
m_rbInteractivePlacement->SetValue( m_placementInteractive );
if( m_rbAbsolutePlacement->GetValue() == m_placementInteractive )
m_rbAbsolutePlacement->SetValue( !m_placementInteractive );
m_xOrigin.Enable( !m_placementInteractive );
m_yOrigin.Enable( !m_placementInteractive );
}

View File

@ -0,0 +1,90 @@
/*
* 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-2022 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 __DIALOG_IMPORT_GFX_SCH_H__
#define __DIALOG_IMPORT_GFX_SCH_H__
#include "dialog_import_gfx_sch_base.h"
#include <import_gfx/graphics_importer.h>
#include <widgets/unit_binder.h>
class SCH_BASE_FRAME;
class GRAPHICS_IMPORT_MGR;
class DIALOG_IMPORT_GFX_SCH : public DIALOG_IMPORT_GFX_SCH_BASE
{
public:
DIALOG_IMPORT_GFX_SCH( SCH_BASE_FRAME* aParent );
~DIALOG_IMPORT_GFX_SCH();
/**
* @return a list of items imported from a vector graphics file.
*/
std::list<std::unique_ptr<EDA_ITEM>>& GetImportedItems()
{
return m_importer->GetItems();
}
/**
* @return true if the placement is interactive, i.e. all imported
* items must be moved by the mouse cursor to the final position
* false means the imported items are placed to the final position after import.
*/
bool IsPlacementInteractive() { return m_placementInteractive; }
bool TransferDataFromWindow() override;
private:
// Virtual event handlers
void onBrowseFiles( wxCommandEvent& event ) override;
void onFilename( wxCommandEvent& event );
void originOptionOnUpdateUI( wxUpdateUIEvent& event ) override;
void onInteractivePlacement( wxCommandEvent& event ) override
{
m_placementInteractive = true;
}
void onAbsolutePlacement( wxCommandEvent& event ) override
{
m_placementInteractive = false;
}
private:
SCH_BASE_FRAME* m_parent;
std::unique_ptr<GRAPHICS_IMPORTER> m_importer;
std::unique_ptr<GRAPHICS_IMPORT_MGR> m_gfxImportMgr;
UNIT_BINDER m_xOrigin;
UNIT_BINDER m_yOrigin;
UNIT_BINDER m_defaultLineWidth;
static bool m_placementInteractive;
static double m_importScale; // a scale factor to change the size of imported
// items m_importScale =1.0 means keep original size
};
#endif // __DIALOG_IMPORT_GFX_SCH_H__

View File

@ -0,0 +1,223 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "widgets/std_bitmap_button.h"
#include "dialog_import_gfx_sch_base.h"
///////////////////////////////////////////////////////////////////////////
DIALOG_IMPORT_GFX_SCH_BASE::DIALOG_IMPORT_GFX_SCH_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bSizerMain;
bSizerMain = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizerFile;
bSizerFile = new wxBoxSizer( wxHORIZONTAL );
m_staticTextFile = new wxStaticText( this, wxID_ANY, _("File:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextFile->Wrap( -1 );
m_staticTextFile->SetToolTip( _("Only vectors will be imported. Bitmaps and fonts will be ignored.") );
bSizerFile->Add( m_staticTextFile, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
m_textCtrlFileName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_textCtrlFileName->SetToolTip( _("Only vectors will be imported. Bitmaps and fonts will be ignored.") );
m_textCtrlFileName->SetMinSize( wxSize( 300,-1 ) );
bSizerFile->Add( m_textCtrlFileName, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_browseButton = new STD_BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), wxBU_AUTODRAW|0 );
bSizerFile->Add( m_browseButton, 0, wxTOP|wxBOTTOM, 5 );
bSizerMain->Add( bSizerFile, 0, wxALL|wxEXPAND, 10 );
wxStaticBoxSizer* sbSizer2;
sbSizer2 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Placement") ), wxVERTICAL );
wxBoxSizer* bSizerOptions;
bSizerOptions = new wxBoxSizer( wxVERTICAL );
m_rbInteractivePlacement = new wxRadioButton( sbSizer2->GetStaticBox(), wxID_ANY, _("Interactive placement"), wxDefaultPosition, wxDefaultSize, 0 );
m_rbInteractivePlacement->SetValue( true );
bSizerOptions->Add( m_rbInteractivePlacement, 0, wxEXPAND|wxBOTTOM, 5 );
wxBoxSizer* bSizerUserPos;
bSizerUserPos = new wxBoxSizer( wxHORIZONTAL );
m_rbAbsolutePlacement = new wxRadioButton( sbSizer2->GetStaticBox(), wxID_ANY, _("At"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerUserPos->Add( m_rbAbsolutePlacement, 0, wxALIGN_CENTER_VERTICAL, 5 );
wxBoxSizer* bSizerPosSettings;
bSizerPosSettings = new wxBoxSizer( wxHORIZONTAL );
m_xLabel = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("X:"), wxDefaultPosition, wxDefaultSize, 0 );
m_xLabel->Wrap( -1 );
bSizerPosSettings->Add( m_xLabel, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_xCtrl = new wxTextCtrl( sbSizer2->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
#ifdef __WXGTK__
if ( !m_xCtrl->HasFlag( wxTE_MULTILINE ) )
{
m_xCtrl->SetMaxLength( 10 );
}
#else
m_xCtrl->SetMaxLength( 10 );
#endif
m_xCtrl->SetToolTip( _("DXF origin on PCB Grid, X Coordinate") );
bSizerPosSettings->Add( m_xCtrl, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
m_xUnits = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_xUnits->Wrap( -1 );
bSizerPosSettings->Add( m_xUnits, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxTOP, 5 );
m_yLabel = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Y:"), wxDefaultPosition, wxDefaultSize, 0 );
m_yLabel->Wrap( -1 );
bSizerPosSettings->Add( m_yLabel, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_yCtrl = new wxTextCtrl( sbSizer2->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
#ifdef __WXGTK__
if ( !m_yCtrl->HasFlag( wxTE_MULTILINE ) )
{
m_yCtrl->SetMaxLength( 10 );
}
#else
m_yCtrl->SetMaxLength( 10 );
#endif
m_yCtrl->SetToolTip( _("DXF origin on PCB Grid, Y Coordinate") );
bSizerPosSettings->Add( m_yCtrl, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
m_yUnits = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_yUnits->Wrap( -1 );
bSizerPosSettings->Add( m_yUnits, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
bSizerUserPos->Add( bSizerPosSettings, 1, wxBOTTOM|wxEXPAND|wxRIGHT|wxTOP, 5 );
bSizerOptions->Add( bSizerUserPos, 0, wxEXPAND, 5 );
sbSizer2->Add( bSizerOptions, 0, wxEXPAND|wxTOP|wxLEFT, 5 );
bSizerMain->Add( sbSizer2, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 10 );
wxStaticBoxSizer* sbSizer1;
sbSizer1 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Import Parameters") ), wxVERTICAL );
wxBoxSizer* bSizer7;
bSizer7 = new wxBoxSizer( wxHORIZONTAL );
wxFlexGridSizer* fgSizerImportSettings;
fgSizerImportSettings = new wxFlexGridSizer( 0, 3, 5, 5 );
fgSizerImportSettings->AddGrowableCol( 1 );
fgSizerImportSettings->SetFlexibleDirection( wxBOTH );
fgSizerImportSettings->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_importScaleLabel = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("Import scale:"), wxDefaultPosition, wxDefaultSize, 0 );
m_importScaleLabel->Wrap( -1 );
fgSizerImportSettings->Add( m_importScaleLabel, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_importScaleCtrl = new wxTextCtrl( sbSizer1->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizerImportSettings->Add( m_importScaleCtrl, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
fgSizerImportSettings->Add( 0, 0, 0, 0, 5 );
bSizer7->Add( fgSizerImportSettings, 1, wxEXPAND|wxALL, 5 );
sbSizer1->Add( bSizer7, 1, wxEXPAND, 5 );
bSizerMain->Add( sbSizer1, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 10 );
wxStaticBoxSizer* sbSizer3;
sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("DXF Parameters") ), wxVERTICAL );
wxBoxSizer* bSizer81;
bSizer81 = new wxBoxSizer( wxHORIZONTAL );
wxFlexGridSizer* fgDxfImportSettings;
fgDxfImportSettings = new wxFlexGridSizer( 0, 3, 5, 5 );
fgDxfImportSettings->AddGrowableCol( 1 );
fgDxfImportSettings->SetFlexibleDirection( wxBOTH );
fgDxfImportSettings->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_lineWidthLabel = new wxStaticText( sbSizer3->GetStaticBox(), wxID_ANY, _("Default line width:"), wxDefaultPosition, wxDefaultSize, 0 );
m_lineWidthLabel->Wrap( -1 );
fgDxfImportSettings->Add( m_lineWidthLabel, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_lineWidthCtrl = new wxTextCtrl( sbSizer3->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgDxfImportSettings->Add( m_lineWidthCtrl, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_lineWidthUnits = new wxStaticText( sbSizer3->GetStaticBox(), wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_lineWidthUnits->Wrap( -1 );
fgDxfImportSettings->Add( m_lineWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxTOP, 5 );
m_staticTextLineWidth1 = new wxStaticText( sbSizer3->GetStaticBox(), wxID_ANY, _("Default units:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextLineWidth1->Wrap( -1 );
fgDxfImportSettings->Add( m_staticTextLineWidth1, 0, wxALIGN_CENTER_VERTICAL, 5 );
wxArrayString m_choiceDxfUnitsChoices;
m_choiceDxfUnits = new wxChoice( sbSizer3->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceDxfUnitsChoices, 0 );
m_choiceDxfUnits->SetSelection( 0 );
fgDxfImportSettings->Add( m_choiceDxfUnits, 0, wxEXPAND, 5 );
fgDxfImportSettings->Add( 0, 0, 1, wxEXPAND, 5 );
bSizer81->Add( fgDxfImportSettings, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
sbSizer3->Add( bSizer81, 1, wxEXPAND, 5 );
bSizerMain->Add( sbSizer3, 1, wxEXPAND|wxRIGHT|wxLEFT, 10 );
m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizerOK = new wxButton( this, wxID_OK );
m_sdbSizer->AddButton( m_sdbSizerOK );
m_sdbSizerCancel = new wxButton( this, wxID_CANCEL );
m_sdbSizer->AddButton( m_sdbSizerCancel );
m_sdbSizer->Realize();
bSizerMain->Add( m_sdbSizer, 0, wxEXPAND|wxALL, 5 );
this->SetSizer( bSizerMain );
this->Layout();
bSizerMain->Fit( this );
this->Centre( wxBOTH );
// Connect Events
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_GFX_SCH_BASE::onBrowseFiles ), NULL, this );
m_rbInteractivePlacement->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_IMPORT_GFX_SCH_BASE::onInteractivePlacement ), NULL, this );
m_rbInteractivePlacement->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_IMPORT_GFX_SCH_BASE::originOptionOnUpdateUI ), NULL, this );
m_rbAbsolutePlacement->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_IMPORT_GFX_SCH_BASE::onAbsolutePlacement ), NULL, this );
m_rbAbsolutePlacement->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_IMPORT_GFX_SCH_BASE::originOptionOnUpdateUI ), NULL, this );
}
DIALOG_IMPORT_GFX_SCH_BASE::~DIALOG_IMPORT_GFX_SCH_BASE()
{
// Disconnect Events
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_GFX_SCH_BASE::onBrowseFiles ), NULL, this );
m_rbInteractivePlacement->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_IMPORT_GFX_SCH_BASE::onInteractivePlacement ), NULL, this );
m_rbInteractivePlacement->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_IMPORT_GFX_SCH_BASE::originOptionOnUpdateUI ), NULL, this );
m_rbAbsolutePlacement->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_IMPORT_GFX_SCH_BASE::onAbsolutePlacement ), NULL, this );
m_rbAbsolutePlacement->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_IMPORT_GFX_SCH_BASE::originOptionOnUpdateUI ), NULL, this );
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class STD_BITMAP_BUTTON;
#include "dialog_shim.h"
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/textctrl.h>
#include <wx/bmpbuttn.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/radiobut.h>
#include <wx/valtext.h>
#include <wx/statbox.h>
#include <wx/choice.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_IMPORT_GFX_SCH_BASE
///////////////////////////////////////////////////////////////////////////////
class DIALOG_IMPORT_GFX_SCH_BASE : public DIALOG_SHIM
{
private:
protected:
wxStaticText* m_staticTextFile;
wxTextCtrl* m_textCtrlFileName;
STD_BITMAP_BUTTON* m_browseButton;
wxRadioButton* m_rbInteractivePlacement;
wxRadioButton* m_rbAbsolutePlacement;
wxStaticText* m_xLabel;
wxTextCtrl* m_xCtrl;
wxStaticText* m_xUnits;
wxStaticText* m_yLabel;
wxTextCtrl* m_yCtrl;
wxStaticText* m_yUnits;
wxStaticText* m_importScaleLabel;
wxTextCtrl* m_importScaleCtrl;
wxStaticText* m_lineWidthLabel;
wxTextCtrl* m_lineWidthCtrl;
wxStaticText* m_lineWidthUnits;
wxStaticText* m_staticTextLineWidth1;
wxChoice* m_choiceDxfUnits;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;
// Virtual event handlers, override them in your derived class
virtual void onBrowseFiles( wxCommandEvent& event ) { event.Skip(); }
virtual void onInteractivePlacement( wxCommandEvent& event ) { event.Skip(); }
virtual void originOptionOnUpdateUI( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onAbsolutePlacement( wxCommandEvent& event ) { event.Skip(); }
public:
DIALOG_IMPORT_GFX_SCH_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Import Vector Graphics File"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_IMPORT_GFX_SCH_BASE();
};

View File

@ -53,7 +53,7 @@ VECTOR2I GRAPHICS_IMPORTER_LIB_SYMBOL::MapCoordinate( const VECTOR2D& aCoordinat
int GRAPHICS_IMPORTER_LIB_SYMBOL::MapLineWidth( double aLineWidth )
{
VECTOR2D factor = ImportScalingFactor();
double scale = ( factor.x + factor.y ) * 0.5;
double scale = ( std::abs( factor.x ) + std::abs( factor.y ) ) * 0.5;
if( aLineWidth <= 0.0 )
return int( GetLineWidthMM() * scale );
@ -63,33 +63,46 @@ int GRAPHICS_IMPORTER_LIB_SYMBOL::MapLineWidth( double aLineWidth )
}
void GRAPHICS_IMPORTER_LIB_SYMBOL::AddLine( const VECTOR2D& aOrigin, const VECTOR2D& aEnd,
double aWidth, const COLOR4D& aColor )
STROKE_PARAMS GRAPHICS_IMPORTER_LIB_SYMBOL::MapStrokeParams( const STROKE_PARAMS& aStroke )
{
std::unique_ptr<LIB_SHAPE> line = std::make_unique<LIB_SHAPE>( m_symbol, SHAPE_T::POLY );
line->SetUnit( m_unit );
line->SetFillColor( aColor );
line->SetStroke( STROKE_PARAMS( MapLineWidth( aWidth ), PLOT_DASH_TYPE::SOLID ) );
line->AddPoint( MapCoordinate( aOrigin ) );
line->AddPoint( MapCoordinate( aEnd ) );
int width = aStroke.GetWidth();
return STROKE_PARAMS( width != -1 ? MapLineWidth( width ) : -1, aStroke.GetPlotStyle(),
aStroke.GetColor() );
}
void GRAPHICS_IMPORTER_LIB_SYMBOL::AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke )
{
VECTOR2I pt0 = MapCoordinate( aStart );
VECTOR2I pt1 = MapCoordinate( aEnd );
// Skip 0 len lines:
if( line->GetStart() == line->GetEnd() )
if( pt0 == pt1 )
return;
std::unique_ptr<LIB_SHAPE> line = std::make_unique<LIB_SHAPE>( m_symbol, SHAPE_T::POLY );
line->SetUnit( m_unit );
line->SetStroke( MapStrokeParams( aStroke ) );
line->AddPoint( pt0 );
line->AddPoint( pt1 );
addItem( std::move( line ) );
}
void GRAPHICS_IMPORTER_LIB_SYMBOL::AddCircle( const VECTOR2D& aCenter, double aRadius, double aWidth,
bool aFilled, const COLOR4D& aColor )
void GRAPHICS_IMPORTER_LIB_SYMBOL::AddCircle( const VECTOR2D& aCenter, double aRadius,
const STROKE_PARAMS& aStroke, bool aFilled,
const COLOR4D& aFillColor )
{
std::unique_ptr<LIB_SHAPE> circle = std::make_unique<LIB_SHAPE>( m_symbol, SHAPE_T::CIRCLE );
circle->SetUnit( m_unit );
circle->SetFillColor( aColor );
circle->SetFillColor( aFillColor );
circle->SetFilled( aFilled );
circle->SetStroke( STROKE_PARAMS( MapLineWidth( aWidth ), PLOT_DASH_TYPE::SOLID ) );
circle->SetStart( MapCoordinate( aCenter ));
circle->SetStroke( MapStrokeParams( aStroke ) );
circle->SetStart( MapCoordinate( aCenter ) );
circle->SetEnd( MapCoordinate( VECTOR2D( aCenter.x + aRadius, aCenter.y ) ) );
addItem( std::move( circle ) );
@ -97,12 +110,10 @@ void GRAPHICS_IMPORTER_LIB_SYMBOL::AddCircle( const VECTOR2D& aCenter, double aR
void GRAPHICS_IMPORTER_LIB_SYMBOL::AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart,
const EDA_ANGLE& aAngle, double aWidth,
const COLOR4D& aColor )
const EDA_ANGLE& aAngle, const STROKE_PARAMS& aStroke )
{
std::unique_ptr<LIB_SHAPE> arc = std::make_unique<LIB_SHAPE>( m_symbol, SHAPE_T::ARC );
arc->SetUnit( m_unit );
arc->SetFillColor( aColor );
/**
* We need to perform the rotation/conversion here while still using floating point values
@ -120,25 +131,26 @@ void GRAPHICS_IMPORTER_LIB_SYMBOL::AddArc( const VECTOR2D& aCenter, const VECTOR
// The criteria used here is radius < MAX_INT / 2.
// this is not perfect, but we do not know the exact final position of the arc, so
// we cannot test the coordinate values, because the arc can be moved before being placed.
VECTOR2D center = CalcArcCenter( arc->GetStart(), arc->GetEnd(), aAngle );
double radius = ( center - arc->GetStart() ).EuclideanNorm();
VECTOR2D center = CalcArcCenter( arc->GetStart(), arc->GetEnd(), aAngle );
double radius = ( center - arc->GetStart() ).EuclideanNorm();
constexpr double rd_max_value = std::numeric_limits<VECTOR2I::coord_type>::max() / 2.0;
if( radius >= rd_max_value )
{
// Arc cannot be handled: convert it to a segment
AddLine( aStart, end, aWidth, aColor );
AddLine( aStart, end, aStroke );
return;
}
arc->SetStroke( STROKE_PARAMS( MapLineWidth( aWidth ), PLOT_DASH_TYPE::SOLID ) );
arc->SetStroke( MapStrokeParams( aStroke ) );
addItem( std::move( arc ) );
}
void GRAPHICS_IMPORTER_LIB_SYMBOL::AddPolygon( const std::vector<VECTOR2D>& aVertices, double aWidth,
const COLOR4D& aColor )
void GRAPHICS_IMPORTER_LIB_SYMBOL::AddPolygon( const std::vector<VECTOR2D>& aVertices,
const STROKE_PARAMS& aStroke, bool aFilled,
const COLOR4D& aFillColor )
{
std::vector<VECTOR2I> convertedPoints;
convertedPoints.reserve( aVertices.size() );
@ -151,24 +163,27 @@ void GRAPHICS_IMPORTER_LIB_SYMBOL::AddPolygon( const std::vector<VECTOR2D>& aVer
std::unique_ptr<LIB_SHAPE> polygon = std::make_unique<LIB_SHAPE>( m_symbol, SHAPE_T::POLY );
polygon->SetUnit( m_unit );
polygon->SetFilled( true );
polygon->SetFillMode( aColor != COLOR4D::UNSPECIFIED ? FILL_T::FILLED_WITH_COLOR
: FILL_T::FILLED_SHAPE );
polygon->SetFillColor( aColor );
if( aFilled )
{
polygon->SetFillMode( aFillColor != COLOR4D::UNSPECIFIED ? FILL_T::FILLED_WITH_COLOR
: FILL_T::FILLED_SHAPE );
}
polygon->SetFillColor( aFillColor );
polygon->SetPolyPoints( convertedPoints );
polygon->AddPoint( convertedPoints[0] ); // Need to close last point for libedit
polygon->SetStroke(
STROKE_PARAMS( aWidth != -1 ? MapLineWidth( aWidth ) : -1, PLOT_DASH_TYPE::SOLID ) );
polygon->SetStroke( MapStrokeParams( aStroke ) );
addItem( std::move( polygon ) );
}
void GRAPHICS_IMPORTER_LIB_SYMBOL::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, const COLOR4D& aColor )
double aHeight, double aWidth, double aThickness,
double aOrientation, GR_TEXT_H_ALIGN_T aHJustify,
GR_TEXT_V_ALIGN_T aVJustify, const COLOR4D& aColor )
{
std::unique_ptr<LIB_TEXT> textItem = std::make_unique<LIB_TEXT>( m_symbol );
textItem->SetUnit( m_unit );
@ -186,29 +201,29 @@ void GRAPHICS_IMPORTER_LIB_SYMBOL::AddText( const VECTOR2D& aOrigin, const wxStr
}
void GRAPHICS_IMPORTER_LIB_SYMBOL::AddSpline( const VECTOR2D& aStart, const VECTOR2D& BezierControl1,
const VECTOR2D& BezierControl2, const VECTOR2D& aEnd,
double aWidth, const COLOR4D& aColor )
void GRAPHICS_IMPORTER_LIB_SYMBOL::AddSpline( const VECTOR2D& aStart,
const VECTOR2D& aBezierControl1,
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke )
{
std::unique_ptr<LIB_SHAPE> spline = std::make_unique<LIB_SHAPE>( m_symbol, SHAPE_T::BEZIER );
spline->SetUnit( m_unit );
spline->SetFillColor( aColor );
spline->SetStroke( STROKE_PARAMS( MapLineWidth( aWidth ), PLOT_DASH_TYPE::SOLID ) );
spline->SetStroke( MapStrokeParams( aStroke ) );
spline->SetStart( MapCoordinate( aStart ) );
spline->SetBezierC1( MapCoordinate( BezierControl1 ));
spline->SetBezierC2( MapCoordinate( BezierControl2 ));
spline->SetBezierC1( MapCoordinate( aBezierControl1 ) );
spline->SetBezierC2( MapCoordinate( aBezierControl2 ) );
spline->SetEnd( MapCoordinate( aEnd ) );
spline->RebuildBezierToSegmentsPointsList( aWidth );
spline->RebuildBezierToSegmentsPointsList( aStroke.GetWidth() );
// If the spline is degenerated (i.e. a segment) add it as segment or discard it if
// null (i.e. very small) length
if( spline->GetBezierPoints().size() <= 2 )
{
spline->SetShape( SHAPE_T::SEGMENT );
int dist = VECTOR2I(spline->GetStart()- spline->GetEnd()).EuclideanNorm();
int dist = VECTOR2I( spline->GetStart() - spline->GetEnd() ).EuclideanNorm();
// segment smaller than MIN_SEG_LEN_ACCEPTABLE_NM nanometers are skipped.
#define MIN_SEG_LEN_ACCEPTABLE_NM 20
// segment smaller than MIN_SEG_LEN_ACCEPTABLE_NM nanometers are skipped.
#define MIN_SEG_LEN_ACCEPTABLE_NM 20
if( dist < MIN_SEG_LEN_ACCEPTABLE_NM )
return;
}

View File

@ -40,25 +40,26 @@ class GRAPHICS_IMPORTER_LIB_SYMBOL : public GRAPHICS_IMPORTER
public:
GRAPHICS_IMPORTER_LIB_SYMBOL( LIB_SYMBOL* aSymbol, int aUnit );
void AddLine( const VECTOR2D& aOrigin, const VECTOR2D& aEnd, double aWidth,
const COLOR4D& aColor ) override;
void AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke ) override;
void AddCircle( const VECTOR2D& aOrigin, double aRadius, double aWidth, bool aFilled,
const COLOR4D& aColor ) override;
void AddCircle( const VECTOR2D& aCenter, double aRadius, const STROKE_PARAMS& aStroke,
bool aFilled, const COLOR4D& aFillColor = COLOR4D::UNSPECIFIED ) override;
void AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart, const EDA_ANGLE& aAngle,
double aWidth, const COLOR4D& aColor ) override;
const STROKE_PARAMS& aStroke ) override;
void AddPolygon( const std::vector<VECTOR2D>& aVertices, double aWidth,
const COLOR4D& aColor ) override;
void AddPolygon( const std::vector<VECTOR2D>& aVertices, const STROKE_PARAMS& aStroke,
bool aFilled, const COLOR4D& aFillColor = COLOR4D::UNSPECIFIED ) override;
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, const COLOR4D& aColor ) override;
GR_TEXT_V_ALIGN_T aVJustify,
const COLOR4D& aColor = COLOR4D::UNSPECIFIED ) override;
void AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd, double aWidth,
const COLOR4D& aColor ) override;
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke ) override;
/**
* Convert an imported coordinate to a board coordinate, according to the internal units,
@ -76,6 +77,8 @@ public:
*/
int MapLineWidth( double aLineWidth );
STROKE_PARAMS MapStrokeParams( const STROKE_PARAMS& aStroke );
LIB_SYMBOL* m_symbol;
int m_unit;
};

View File

@ -61,7 +61,15 @@ void SYMBOL_EDIT_FRAME::doReCreateMenuBar()
fileMenu->Add( ACTIONS::revert );
fileMenu->AppendSeparator();
fileMenu->Add( EE_ACTIONS::importSymbol );
ACTION_MENU* submenuImport = new ACTION_MENU( false, selTool );
submenuImport->SetTitle( _( "Import" ) );
submenuImport->SetIcon( BITMAPS::import );
submenuImport->Add( EE_ACTIONS::importSymbol, ACTION_MENU::NORMAL, _( "Symbol..." ) );
submenuImport->Add( EE_ACTIONS::symbolImportGraphics, ACTION_MENU::NORMAL, _( "Graphics..." ) );
fileMenu->Add( submenuImport );
// Export submenu
ACTION_MENU* submenuExport = new ACTION_MENU( false, selTool );

View File

@ -540,6 +540,7 @@ void SYMBOL_EDIT_FRAME::setupUIConditions()
mgr->SetConditions( EE_ACTIONS::drawSymbolLines, EDIT_TOOL( EE_ACTIONS::drawSymbolLines ) );
mgr->SetConditions( EE_ACTIONS::drawSymbolPolygon, EDIT_TOOL( EE_ACTIONS::drawSymbolPolygon ) );
mgr->SetConditions( EE_ACTIONS::placeSymbolAnchor, EDIT_TOOL( EE_ACTIONS::placeSymbolAnchor ) );
mgr->SetConditions( EE_ACTIONS::symbolImportGraphics, EDIT_TOOL( EE_ACTIONS::symbolImportGraphics ) );
#undef CHECK
#undef ENABLE

View File

@ -36,6 +36,7 @@ SYMBOL_EDITOR_SETTINGS::SYMBOL_EDITOR_SETTINGS() :
APP_SETTINGS_BASE( "symbol_editor", libeditSchemaVersion ),
m_Defaults(),
m_Repeat(),
m_ImportGraphics(),
m_ShowPinElectricalType( true ),
m_LibWidth(),
m_EditSymbolVisibleColumns()
@ -76,6 +77,27 @@ SYMBOL_EDITOR_SETTINGS::SYMBOL_EDITOR_SETTINGS() :
m_params.emplace_back( new PARAM<int>( "repeat.pin_step",
&m_Repeat.pin_step, 100 ) );
m_params.emplace_back( new PARAM<bool>( "import_graphics.interactive_placement",
&m_ImportGraphics.interactive_placement, true ) );
m_params.emplace_back( new PARAM<int>( "import_graphics.line_width_units",
&m_ImportGraphics.dxf_line_width_units, 0 ) );
m_params.emplace_back( new PARAM<double>( "import_graphics.line_width",
&m_ImportGraphics.dxf_line_width, 0.2 ) );
m_params.emplace_back( new PARAM<int>( "import_graphics.origin_units",
&m_ImportGraphics.origin_units, 0 ) );
m_params.emplace_back( new PARAM<double>( "import_graphics.origin_x",
&m_ImportGraphics.origin_x, 0 ) );
m_params.emplace_back( new PARAM<double>( "import_graphics.origin_y",
&m_ImportGraphics.origin_y, 0 ) );
m_params.emplace_back( new PARAM<int>( "import_graphics.dxf_units",
&m_ImportGraphics.dxf_units, 0 ) );
m_params.emplace_back( new PARAM<bool>( "show_pin_electrical_type",
&m_ShowPinElectricalType, true ) );

View File

@ -53,6 +53,18 @@ public:
int pin_step;
};
struct DIALOG_IMPORT_GRAPHICS
{
bool interactive_placement;
wxString last_file;
double dxf_line_width;
int dxf_line_width_units;
int origin_units;
double origin_x;
double origin_y;
int dxf_units;
};
SYMBOL_EDITOR_SETTINGS();
virtual ~SYMBOL_EDITOR_SETTINGS() {}
@ -65,6 +77,8 @@ public:
REPEAT m_Repeat;
DIALOG_IMPORT_GRAPHICS m_ImportGraphics;
bool m_ShowPinElectricalType;
int m_LibWidth;

View File

@ -369,6 +369,16 @@ TOOL_ACTION EE_ACTIONS::placeSymbolAnchor( TOOL_ACTION_ARGS()
.Icon( BITMAPS::anchor )
.Flags( AF_ACTIVATE ) );
TOOL_ACTION EE_ACTIONS::symbolImportGraphics( TOOL_ACTION_ARGS()
.Name( "eeschema.SymbolDrawing.symbolImportGraphics" )
.Scope( AS_GLOBAL )
.DefaultHotkey( MD_SHIFT + MD_CTRL + 'F' )
.LegacyHotkeyName( "Place DXF" )
.MenuText( _( "Import Graphics..." ) )
.Tooltip( _( "Import 2D drawing file" ) )
.Icon( BITMAPS::import_vector )
.Flags( AF_ACTIVATE ) );
TOOL_ACTION EE_ACTIONS::finishDrawing( TOOL_ACTION_ARGS()
.Name( "eeschema.SymbolDrawing.finishDrawing" )
.Scope( AS_GLOBAL )

View File

@ -112,6 +112,7 @@ public:
static TOOL_ACTION drawSymbolLines;
static TOOL_ACTION drawSymbolPolygon;
static TOOL_ACTION placeSymbolAnchor;
static TOOL_ACTION symbolImportGraphics;
static TOOL_ACTION finishDrawing;
// Interactive Editing

View File

@ -38,6 +38,9 @@
#include <symbol_editor/symbol_editor_settings.h>
#include <settings/settings_manager.h>
#include <string_utils.h>
#include <geometry/geometry_utils.h>
#include <wx/msgdlg.h>
#include <import_gfx/dialog_import_gfx_sch.h>
#include "dialog_lib_textbox_properties.h"
static void* g_lastPinWeakPtr;
@ -651,6 +654,173 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::PlaceAnchor( const TOOL_EVENT& aEvent )
}
int SYMBOL_EDITOR_DRAWING_TOOLS::SymbolImportGraphics( const TOOL_EVENT& aEvent )
{
LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
if( !symbol )
return 0;
// Note: PlaceImportedGraphics() will convert PCB_SHAPE_T and PCB_TEXT_T to footprint
// items if needed
DIALOG_IMPORT_GFX_SCH dlg( m_frame );
int dlgResult = dlg.ShowModal();
std::list<std::unique_ptr<EDA_ITEM>>& list = dlg.GetImportedItems();
if( dlgResult != wxID_OK )
return 0;
// Ensure the list is not empty:
if( list.empty() )
{
wxMessageBox( _( "No graphic items found in file." ) );
return 0;
}
m_toolMgr->RunAction( ACTIONS::cancelInteractive );
KIGFX::VIEW_CONTROLS* controls = getViewControls();
std::vector<LIB_ITEM*> newItems; // all new items, including group
std::vector<LIB_ITEM*> selectedItems; // the group, or newItems if no group
EE_SELECTION preview;
SCH_COMMIT commit( m_toolMgr );
for( std::unique_ptr<EDA_ITEM>& ptr : list )
{
LIB_ITEM* item = dynamic_cast<LIB_ITEM*>( ptr.get() );
wxCHECK2( item, continue );
newItems.push_back( item );
selectedItems.push_back( item );
preview.Add( item );
ptr.release();
}
if( !dlg.IsPlacementInteractive() )
{
commit.Modify( symbol, m_frame->GetScreen() );
// Place the imported drawings
for( LIB_ITEM* item : newItems )
{
symbol->AddDrawItem( item );
item->ClearEditFlags();
}
commit.Push( _( "Import Graphic" ) );
m_frame->RebuildView();
return 0;
}
m_view->Add( &preview );
// Clear the current selection then select the drawings so that edit tools work on them
m_toolMgr->RunAction( EE_ACTIONS::clearSelection );
EDA_ITEMS selItems( selectedItems.begin(), selectedItems.end() );
m_toolMgr->RunAction<EDA_ITEMS*>( EE_ACTIONS::addItemsToSel, &selItems );
m_frame->PushTool( aEvent );
auto setCursor = [&]()
{
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
};
Activate();
// Must be done after Activate() so that it gets set into the correct context
controls->ShowCursor( true );
controls->ForceCursorPosition( false );
// Set initial cursor
setCursor();
//SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF );
EE_GRID_HELPER grid( m_toolMgr );
// Now move the new items to the current cursor position:
VECTOR2I cursorPos = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
VECTOR2I delta = cursorPos;
VECTOR2I currentOffset;
for( LIB_ITEM* item : selectedItems )
item->Offset( delta );
currentOffset += delta;
m_view->Update( &preview );
// Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() )
{
setCursor();
grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
cursorPos = grid.Align( controls->GetMousePosition(), GRID_GRAPHICS );
controls->ForceCursorPosition( true, cursorPos );
if( evt->IsCancelInteractive() || evt->IsActivate() )
{
m_toolMgr->RunAction( EE_ACTIONS::clearSelection );
for( LIB_ITEM* item : newItems )
delete item;
break;
}
else if( evt->IsMotion() )
{
delta = VECTOR2I( cursorPos.x, -cursorPos.y ) - currentOffset;
for( LIB_ITEM* item : selectedItems )
item->Offset( delta );
currentOffset += delta;
m_view->Update( &preview );
}
else if( evt->IsClick( BUT_RIGHT ) )
{
m_menu.ShowContextMenu( m_selectionTool->GetSelection() );
}
else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
{
commit.Modify( symbol, m_frame->GetScreen() );
// Place the imported drawings
for( LIB_ITEM* item : newItems )
{
symbol->AddDrawItem( item );
item->ClearEditFlags();
}
commit.Push( _( "Import Graphic" ) );
break; // This is a one-shot command, not a tool
}
else
{
evt->SetPassEvent();
}
}
preview.Clear();
m_view->Remove( &preview );
m_frame->RebuildView();
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
controls->ForceCursorPosition( false );
m_frame->PopTool( aEvent );
return 0;
}
int SYMBOL_EDITOR_DRAWING_TOOLS::RepeatDrawItem( const TOOL_EVENT& aEvent )
{
SYMBOL_EDITOR_PIN_TOOL* pinTool = m_toolMgr->GetTool<SYMBOL_EDITOR_PIN_TOOL>();
@ -698,5 +868,6 @@ void SYMBOL_EDITOR_DRAWING_TOOLS::setTransitions()
Go( &SYMBOL_EDITOR_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawSymbolPolygon.MakeEvent() );
Go( &SYMBOL_EDITOR_DRAWING_TOOLS::DrawSymbolTextBox, EE_ACTIONS::drawSymbolTextBox.MakeEvent() );
Go( &SYMBOL_EDITOR_DRAWING_TOOLS::PlaceAnchor, EE_ACTIONS::placeSymbolAnchor.MakeEvent() );
Go( &SYMBOL_EDITOR_DRAWING_TOOLS::SymbolImportGraphics, EE_ACTIONS::symbolImportGraphics.MakeEvent() );
Go( &SYMBOL_EDITOR_DRAWING_TOOLS::RepeatDrawItem, EE_ACTIONS::repeatDrawItem.MakeEvent() );
}

View File

@ -52,6 +52,7 @@ public:
int DrawShape( const TOOL_EVENT& aEvent );
int DrawSymbolTextBox( const TOOL_EVENT& aEvent );
int PlaceAnchor( const TOOL_EVENT& aEvent );
int SymbolImportGraphics( const TOOL_EVENT& aEvent );
int RepeatDrawItem( const TOOL_EVENT& aEvent );

View File

@ -64,14 +64,23 @@ int GRAPHICS_IMPORTER_PCBNEW::MapLineWidth( double aLineWidth )
}
void GRAPHICS_IMPORTER_PCBNEW::AddLine( const VECTOR2D& aOrigin, const VECTOR2D& aEnd,
double aWidth, const COLOR4D& aColor )
STROKE_PARAMS GRAPHICS_IMPORTER_PCBNEW::MapStrokeParams( const STROKE_PARAMS& aStroke )
{
int width = aStroke.GetWidth();
return STROKE_PARAMS( width != -1 ? MapLineWidth( width ) : -1, aStroke.GetPlotStyle(),
aStroke.GetColor() );
}
void GRAPHICS_IMPORTER_PCBNEW::AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke )
{
std::unique_ptr<PCB_SHAPE> line( createDrawing() );
line->SetShape( SHAPE_T::SEGMENT );
line->SetLayer( GetLayer() );
line->SetStroke( STROKE_PARAMS( MapLineWidth( aWidth ), PLOT_DASH_TYPE::SOLID ) );
line->SetStart( MapCoordinate( aOrigin ) );
line->SetStroke( MapStrokeParams( aStroke ) );
line->SetStart( MapCoordinate( aStart ) );
line->SetEnd( MapCoordinate( aEnd ) );
// Skip 0 len lines:
@ -82,15 +91,16 @@ void GRAPHICS_IMPORTER_PCBNEW::AddLine( const VECTOR2D& aOrigin, const VECTOR2D&
}
void GRAPHICS_IMPORTER_PCBNEW::AddCircle( const VECTOR2D& aCenter, double aRadius, double aWidth,
bool aFilled, const COLOR4D& aColor )
void GRAPHICS_IMPORTER_PCBNEW::AddCircle( const VECTOR2D& aCenter, double aRadius,
const STROKE_PARAMS& aStroke, bool aFilled,
const COLOR4D& aFillColor )
{
std::unique_ptr<PCB_SHAPE> circle( createDrawing() );
circle->SetShape( SHAPE_T::CIRCLE );
circle->SetFilled( aFilled );
circle->SetLayer( GetLayer() );
circle->SetStroke( STROKE_PARAMS( MapLineWidth( aWidth ), PLOT_DASH_TYPE::SOLID ) );
circle->SetStart( MapCoordinate( aCenter ));
circle->SetStroke( MapStrokeParams( aStroke ) );
circle->SetStart( MapCoordinate( aCenter ) );
circle->SetEnd( MapCoordinate( VECTOR2D( aCenter.x + aRadius, aCenter.y ) ) );
addItem( std::move( circle ) );
@ -98,8 +108,7 @@ void GRAPHICS_IMPORTER_PCBNEW::AddCircle( const VECTOR2D& aCenter, double aRadiu
void GRAPHICS_IMPORTER_PCBNEW::AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart,
const EDA_ANGLE& aAngle, double aWidth,
const COLOR4D& aColor )
const EDA_ANGLE& aAngle, const STROKE_PARAMS& aStroke )
{
std::unique_ptr<PCB_SHAPE> arc( createDrawing() );
arc->SetShape( SHAPE_T::ARC );
@ -128,18 +137,19 @@ void GRAPHICS_IMPORTER_PCBNEW::AddArc( const VECTOR2D& aCenter, const VECTOR2D&
if( radius >= rd_max_value )
{
// Arc cannot be handled: convert it to a segment
AddLine( aStart, end, aWidth, aColor );
AddLine( aStart, end, aStroke );
return;
}
arc->SetStroke( STROKE_PARAMS( MapLineWidth( aWidth ), PLOT_DASH_TYPE::SOLID ) );
arc->SetStroke( MapStrokeParams( aStroke ) );
addItem( std::move( arc ) );
}
void GRAPHICS_IMPORTER_PCBNEW::AddPolygon( const std::vector<VECTOR2D>& aVertices, double aWidth,
const COLOR4D& aColor )
void GRAPHICS_IMPORTER_PCBNEW::AddPolygon( const std::vector<VECTOR2D>& aVertices,
const STROKE_PARAMS& aStroke, bool aFilled,
const COLOR4D& aFillColor )
{
std::vector<VECTOR2I> convertedPoints;
convertedPoints.reserve( aVertices.size() );
@ -159,7 +169,7 @@ void GRAPHICS_IMPORTER_PCBNEW::AddPolygon( const std::vector<VECTOR2D>& aVertice
polygon->Move( parentFP->GetPosition() );
}
polygon->SetStroke( STROKE_PARAMS( MapLineWidth( aWidth ), PLOT_DASH_TYPE::SOLID ) );
polygon->SetStroke( MapStrokeParams( aStroke ) );
addItem( std::move( polygon ) );
}
@ -184,19 +194,19 @@ void GRAPHICS_IMPORTER_PCBNEW::AddText( const VECTOR2D& aOrigin, const wxString&
}
void GRAPHICS_IMPORTER_PCBNEW::AddSpline( const VECTOR2D& aStart, const VECTOR2D& BezierControl1,
const VECTOR2D& BezierControl2, const VECTOR2D& aEnd,
double aWidth, const COLOR4D& aColor )
void GRAPHICS_IMPORTER_PCBNEW::AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke )
{
std::unique_ptr<PCB_SHAPE> spline( createDrawing() );
spline->SetShape( SHAPE_T::BEZIER );
spline->SetLayer( GetLayer() );
spline->SetStroke( STROKE_PARAMS( MapLineWidth( aWidth ), PLOT_DASH_TYPE::SOLID ) );
spline->SetStroke( MapStrokeParams( aStroke ) );
spline->SetStart( MapCoordinate( aStart ) );
spline->SetBezierC1( MapCoordinate( BezierControl1 ));
spline->SetBezierC2( MapCoordinate( BezierControl2 ));
spline->SetBezierC1( MapCoordinate( aBezierControl1 ));
spline->SetBezierC2( MapCoordinate( aBezierControl2 ));
spline->SetEnd( MapCoordinate( aEnd ) );
spline->RebuildBezierToSegmentsPointsList( aWidth );
spline->RebuildBezierToSegmentsPointsList( aStroke.GetWidth() );
// If the spline is degenerated (i.e. a segment) add it as segment or discard it if
// null (i.e. very small) length

View File

@ -59,25 +59,26 @@ public:
return m_layer;
}
void AddLine( const VECTOR2D& aOrigin, const VECTOR2D& aEnd, double aWidth,
const COLOR4D& aColor ) override;
void AddLine( const VECTOR2D& aStart, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke ) override;
void AddCircle( const VECTOR2D& aOrigin, double aRadius, double aWidth, bool aFilled,
const COLOR4D& aColor ) override;
void AddCircle( const VECTOR2D& aCenter, double aRadius, const STROKE_PARAMS& aStroke,
bool aFilled, const COLOR4D& aFillColor = COLOR4D::UNSPECIFIED ) override;
void AddArc( const VECTOR2D& aCenter, const VECTOR2D& aStart, const EDA_ANGLE& aAngle,
double aWidth, const COLOR4D& aColor ) override;
const STROKE_PARAMS& aStroke ) override;
void AddPolygon( const std::vector<VECTOR2D>& aVertices, double aWidth,
const COLOR4D& aColor ) override;
void AddPolygon( const std::vector<VECTOR2D>& aVertices, const STROKE_PARAMS& aStroke,
bool aFilled, const COLOR4D& aFillColor = COLOR4D::UNSPECIFIED ) override;
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, const COLOR4D& aColor ) override;
GR_TEXT_V_ALIGN_T aVJustify,
const COLOR4D& aColor = COLOR4D::UNSPECIFIED ) override;
void AddSpline( const VECTOR2D& aStart, const VECTOR2D& aBezierControl1,
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd, double aWidth,
const COLOR4D& aColor ) override;
const VECTOR2D& aBezierControl2, const VECTOR2D& aEnd,
const STROKE_PARAMS& aStroke ) override;
/**
* Convert an imported coordinate to a board coordinate, according to the internal units,
@ -95,6 +96,8 @@ public:
*/
int MapLineWidth( double aLineWidth );
STROKE_PARAMS MapStrokeParams( const STROKE_PARAMS& aStroke );
protected:
///< Create an object representing a graphical shape.
virtual std::unique_ptr<PCB_SHAPE> createDrawing() = 0;