pcbnew: GRAPHICS_IMPORTER can now recognize multi-path shapes (and postprocess polygons with holes into Kicad-compatible fractured polysets)
This commit is contained in:
parent
78968f75c0
commit
5d87b37f52
|
@ -78,3 +78,9 @@ bool GRAPHICS_IMPORTER::Import( double aScale )
|
|||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
void GRAPHICS_IMPORTER::NewShape( POLY_FILL_RULE aFillRule )
|
||||
{
|
||||
m_shapeFillRules.push_back( aFillRule );
|
||||
}
|
||||
|
|
|
@ -45,6 +45,12 @@ class EDA_ITEM;
|
|||
class GRAPHICS_IMPORTER
|
||||
{
|
||||
public:
|
||||
enum POLY_FILL_RULE
|
||||
{
|
||||
PF_NONZERO = 0,
|
||||
PF_EVEN_ODD
|
||||
};
|
||||
|
||||
GRAPHICS_IMPORTER();
|
||||
|
||||
virtual ~GRAPHICS_IMPORTER()
|
||||
|
@ -186,6 +192,8 @@ public:
|
|||
///< Default line thickness (in mm)
|
||||
static constexpr unsigned int DEFAULT_LINE_WIDTH_DFX = 1;
|
||||
|
||||
virtual void NewShape( POLY_FILL_RULE aFillRule = PF_NONZERO );
|
||||
|
||||
/**
|
||||
* Create an object representing a line segment.
|
||||
*
|
||||
|
@ -261,6 +269,8 @@ protected:
|
|||
///< Offset (in mm) for imported coordinates
|
||||
VECTOR2D m_offsetCoordmm;
|
||||
|
||||
std::vector<POLY_FILL_RULE> m_shapeFillRules;
|
||||
|
||||
private:
|
||||
///< List of imported items
|
||||
std::list<std::unique_ptr<EDA_ITEM>> m_items;
|
||||
|
|
|
@ -86,3 +86,119 @@ void GRAPHICS_IMPORTER_BUFFER::ImportTo( GRAPHICS_IMPORTER& aImporter )
|
|||
for( std::unique_ptr<IMPORTED_SHAPE>& shape : m_shapes )
|
||||
shape->ImportTo( 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,
|
||||
int aWidth )
|
||||
{
|
||||
double minX = std::numeric_limits<double>::max();
|
||||
double minY = minX;
|
||||
double maxX = std::numeric_limits<double>::min();
|
||||
double maxY = maxX;
|
||||
|
||||
// as Clipper/SHAPE_POLY_SET uses ints we first need to upscale to a reasonably large size (in integer coordinates)
|
||||
// to avoid loosing accuracy
|
||||
const double convert_scale = 1000000000.0;
|
||||
|
||||
for( IMPORTED_POLYGON* path : aPaths )
|
||||
{
|
||||
for( VECTOR2D& v : path->Vertices() )
|
||||
{
|
||||
minX = std::min( minX, v.x );
|
||||
minY = std::min( minY, v.y );
|
||||
maxX = std::max( maxX, v.x );
|
||||
maxY = std::max( maxY, v.y );
|
||||
}
|
||||
}
|
||||
|
||||
double origW = ( maxX - minX );
|
||||
double origH = ( maxY - minY );
|
||||
double upscaledW, upscaledH;
|
||||
|
||||
if( origW > origH )
|
||||
{
|
||||
upscaledW = convert_scale;
|
||||
upscaledH = ( origH == 0.0f ? 0.0 : origH * convert_scale / origW );
|
||||
}
|
||||
else
|
||||
{
|
||||
upscaledH = convert_scale;
|
||||
upscaledW = ( origW == 0.0f ? 0.0 : origW * convert_scale / origH );
|
||||
}
|
||||
|
||||
std::vector<SHAPE_LINE_CHAIN> upscaledPaths;
|
||||
|
||||
for( IMPORTED_POLYGON* path : aPaths )
|
||||
{
|
||||
SHAPE_LINE_CHAIN lc;
|
||||
|
||||
for( VECTOR2D& v : path->Vertices() )
|
||||
{
|
||||
int xp = KiROUND( ( v.x - minX ) * ( upscaledW / origW ) );
|
||||
int yp = KiROUND( ( v.y - minY ) * ( upscaledH / origH ) );
|
||||
lc.Append( xp, yp );
|
||||
}
|
||||
lc.SetClosed( true );
|
||||
upscaledPaths.push_back( lc );
|
||||
}
|
||||
|
||||
SHAPE_POLY_SET result = SHAPE_POLY_SET::BuildPolysetFromOrientedPaths(
|
||||
upscaledPaths, false, aFillRule == GRAPHICS_IMPORTER::PF_EVEN_ODD );
|
||||
result.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
||||
|
||||
for( int outl = 0; outl < result.OutlineCount(); outl++ )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& ro = result.COutline( outl );
|
||||
std::vector<VECTOR2D> pts;
|
||||
for( int i = 0; i < ro.PointCount(); i++ )
|
||||
{
|
||||
double xp = (double) ro.CPoint( i ).x * ( origW / upscaledW ) + minX;
|
||||
double yp = (double) ro.CPoint( i ).y * ( origH / upscaledH ) + minY;
|
||||
pts.emplace_back( VECTOR2D( xp, yp ) );
|
||||
}
|
||||
|
||||
aShapes.push_back( std::make_unique<IMPORTED_POLYGON>( pts, aWidth ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GRAPHICS_IMPORTER_BUFFER::PostprocessNestedPolygons()
|
||||
{
|
||||
int curShapeIdx = 0;
|
||||
int lastWidth = 1;
|
||||
|
||||
std::list<std::unique_ptr<IMPORTED_SHAPE>> newShapes;
|
||||
std::vector<IMPORTED_POLYGON*> polypaths;
|
||||
|
||||
for( auto& shape : m_shapes )
|
||||
{
|
||||
IMPORTED_POLYGON* poly = dynamic_cast<IMPORTED_POLYGON*>( shape.get() );
|
||||
|
||||
if( !poly || poly->GetParentShapeIndex() < 0 )
|
||||
{
|
||||
newShapes.push_back( shape->clone() );
|
||||
continue;
|
||||
}
|
||||
|
||||
lastWidth = poly->GetWidth();
|
||||
int index = poly->GetParentShapeIndex();
|
||||
|
||||
if( index == curShapeIdx )
|
||||
{
|
||||
polypaths.push_back( poly );
|
||||
}
|
||||
else if( index == curShapeIdx + 1 )
|
||||
{
|
||||
convertPolygon( newShapes, polypaths, m_shapeFillRules[curShapeIdx], lastWidth );
|
||||
curShapeIdx++;
|
||||
polypaths.clear();
|
||||
polypaths.push_back( poly );
|
||||
}
|
||||
}
|
||||
|
||||
convertPolygon( newShapes, polypaths, m_shapeFillRules[curShapeIdx], lastWidth );
|
||||
|
||||
m_shapes.swap( newShapes );
|
||||
}
|
||||
|
|
|
@ -41,6 +41,12 @@ public:
|
|||
|
||||
virtual void Translate( const VECTOR2D& aVec ) = 0;
|
||||
virtual void Scale( double scaleX, double scaleY ) = 0;
|
||||
|
||||
void SetParentShapeIndex( int aIndex ) { m_parentShapeIndex = aIndex; }
|
||||
int GetParentShapeIndex() const { return m_parentShapeIndex; }
|
||||
|
||||
protected:
|
||||
int m_parentShapeIndex = -1;
|
||||
};
|
||||
|
||||
|
||||
|
@ -208,6 +214,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<VECTOR2D>& Vertices() { return m_vertices; }
|
||||
|
||||
int GetWidth() const { return m_width; }
|
||||
|
||||
private:
|
||||
std::vector<VECTOR2D> m_vertices;
|
||||
double m_width;
|
||||
|
@ -344,6 +354,8 @@ public:
|
|||
return m_shapes;
|
||||
}
|
||||
|
||||
void PostprocessNestedPolygons();
|
||||
|
||||
protected:
|
||||
///< List of imported shapes
|
||||
std::list< std::unique_ptr< IMPORTED_SHAPE > > m_shapes;
|
||||
|
|
Loading…
Reference in New Issue