2018-10-13 18:37:28 +00:00
/*
* This program source code file is part of KICAD , a free EDA CAD application .
*
* Copyright ( C ) 2017 CERN
* @ author Janito Vaqueiro Ferreira Filho < janito . vff @ gmail . com >
*
* 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
*/
2020-10-14 02:46:39 +00:00
# include <eda_item.h>
2021-12-30 02:48:44 +00:00
# include <geometry/shape_line_chain.h>
# include <geometry/shape_poly_set.h>
2018-10-13 18:37:28 +00:00
# include "graphics_importer_buffer.h"
using namespace std ;
template < typename T , typename . . . Args >
static std : : unique_ptr < T > make_shape ( const Args & . . . aArguments )
{
2020-10-26 23:49:11 +00:00
return std : : make_unique < T > ( aArguments . . . ) ;
2018-10-13 18:37:28 +00:00
}
2018-11-05 16:04:05 +00:00
void GRAPHICS_IMPORTER_BUFFER : : AddLine ( const VECTOR2D & aStart , const VECTOR2D & aEnd , double aWidth )
2018-10-13 18:37:28 +00:00
{
2018-11-05 16:04:05 +00:00
m_shapes . push_back ( make_shape < IMPORTED_LINE > ( aStart , aEnd , aWidth ) ) ;
2018-10-13 18:37:28 +00:00
}
2020-11-20 01:07:08 +00:00
void GRAPHICS_IMPORTER_BUFFER : : AddCircle ( const VECTOR2D & aCenter , double aRadius , double aWidth , bool aFilled )
2018-10-13 18:37:28 +00:00
{
2020-11-20 01:07:08 +00:00
m_shapes . push_back ( make_shape < IMPORTED_CIRCLE > ( aCenter , aRadius , aWidth , aFilled ) ) ;
2018-10-13 18:37:28 +00:00
}
void GRAPHICS_IMPORTER_BUFFER : : AddArc ( const VECTOR2D & aCenter , const VECTOR2D & aStart ,
2018-11-05 16:04:05 +00:00
double aAngle , double aWidth )
2018-10-13 18:37:28 +00:00
{
2018-11-05 16:04:05 +00:00
m_shapes . push_back ( make_shape < IMPORTED_ARC > ( aCenter , aStart , aAngle , aWidth ) ) ;
2018-10-13 18:37:28 +00:00
}
2018-11-05 16:04:05 +00:00
void GRAPHICS_IMPORTER_BUFFER : : AddPolygon ( const std : : vector < VECTOR2D > & aVertices , double aWidth )
2018-10-13 18:37:28 +00:00
{
2018-11-05 16:04:05 +00:00
m_shapes . push_back ( make_shape < IMPORTED_POLYGON > ( aVertices , aWidth ) ) ;
2021-12-30 02:48:44 +00:00
m_shapes . back ( ) - > SetParentShapeIndex ( m_shapeFillRules . size ( ) - 1 ) ;
2018-10-13 18:37:28 +00:00
}
void GRAPHICS_IMPORTER_BUFFER : : AddText ( const VECTOR2D & aOrigin , const wxString & aText ,
2018-12-04 19:01:47 +00:00
double aHeight , double aWidth , double aThickness , double aOrientation ,
2018-10-13 18:37:28 +00:00
EDA_TEXT_HJUSTIFY_T aHJustify , EDA_TEXT_VJUSTIFY_T aVJustify )
{
2018-12-04 19:01:47 +00:00
m_shapes . push_back ( make_shape < IMPORTED_TEXT > ( aOrigin , aText , aHeight , aWidth ,
aThickness , aOrientation , aHJustify , aVJustify ) ) ;
2018-10-13 18:37:28 +00:00
}
2018-11-01 09:47:41 +00:00
void GRAPHICS_IMPORTER_BUFFER : : AddSpline ( const VECTOR2D & aStart , const VECTOR2D & aBezierControl1 ,
const VECTOR2D & aBezierControl2 , const VECTOR2D & aEnd , double aWidth )
{
m_shapes . push_back ( make_shape < IMPORTED_SPLINE > ( aStart , aBezierControl1 , aBezierControl2 , aEnd , aWidth ) ) ;
}
2020-11-23 14:59:00 +00:00
void GRAPHICS_IMPORTER_BUFFER : : AddShape ( std : : unique_ptr < IMPORTED_SHAPE > & aShape )
{
m_shapes . push_back ( std : : move ( aShape ) ) ;
}
2018-10-13 18:37:28 +00:00
void GRAPHICS_IMPORTER_BUFFER : : ImportTo ( GRAPHICS_IMPORTER & aImporter )
{
for ( auto & shape : m_shapes )
shape - > ImportTo ( aImporter ) ;
}
2021-12-30 02:48:44 +00:00
// 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 = - 1 ;
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 ( curShapeIdx < 0 )
index = curShapeIdx ;
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 ) ;
}
}
2022-02-27 08:59:42 +00:00
POLY_FILL_RULE last_rule = ( curShapeIdx > = 0 & & m_shapeFillRules . size ( ) )
? m_shapeFillRules [ curShapeIdx ]
: POLY_FILL_RULE : : PF_EVEN_ODD ;
convertPolygon ( newShapes , polypaths , last_rule , lastWidth ) ;
2021-12-30 02:48:44 +00:00
m_shapes . swap ( newShapes ) ;
}