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
2023-08-18 18:27:48 +00:00
* Copyright ( C ) 2021 - 2023 KiCad Developers , see AUTHORS . txt for contributors .
2018-10-13 18:37:28 +00:00
* @ 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-31 14:27:09 +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
}
2023-10-09 00:54:34 +00:00
void GRAPHICS_IMPORTER_BUFFER : : AddLine ( const VECTOR2D & aStart , const VECTOR2D & aEnd ,
2023-10-09 03:56:13 +00:00
const IMPORTED_STROKE & aStroke )
2018-10-13 18:37:28 +00:00
{
2023-10-09 00:54:34 +00:00
m_shapes . push_back ( make_shape < IMPORTED_LINE > ( aStart , aEnd , aStroke ) ) ;
2018-10-13 18:37:28 +00:00
}
2023-10-09 00:54:34 +00:00
void GRAPHICS_IMPORTER_BUFFER : : AddCircle ( const VECTOR2D & aCenter , double aRadius ,
2023-10-09 03:56:13 +00:00
const IMPORTED_STROKE & aStroke , bool aFilled ,
2023-10-09 00:54:34 +00:00
const COLOR4D & aFillColor )
2018-10-13 18:37:28 +00:00
{
2023-10-09 00:54:34 +00:00
m_shapes . push_back (
make_shape < IMPORTED_CIRCLE > ( aCenter , aRadius , aStroke , aFilled , aFillColor ) ) ;
2018-10-13 18:37:28 +00:00
}
void GRAPHICS_IMPORTER_BUFFER : : AddArc ( const VECTOR2D & aCenter , const VECTOR2D & aStart ,
2023-10-09 03:56:13 +00:00
const EDA_ANGLE & aAngle , const IMPORTED_STROKE & aStroke )
2018-10-13 18:37:28 +00:00
{
2023-10-09 00:54:34 +00:00
m_shapes . push_back ( make_shape < IMPORTED_ARC > ( aCenter , aStart , aAngle , aStroke ) ) ;
2018-10-13 18:37:28 +00:00
}
2023-10-09 00:54:34 +00:00
void GRAPHICS_IMPORTER_BUFFER : : AddPolygon ( const std : : vector < VECTOR2D > & aVertices ,
2023-10-09 03:56:13 +00:00
const IMPORTED_STROKE & aStroke , bool aFilled ,
2023-10-09 00:54:34 +00:00
const COLOR4D & aFillColor )
2018-10-13 18:37:28 +00:00
{
2023-10-09 00:54:34 +00:00
m_shapes . push_back ( make_shape < IMPORTED_POLYGON > ( aVertices , aStroke , aFilled , aFillColor ) ) ;
2021-12-31 14:27:09 +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 ,
2021-12-28 22:13:54 +00:00
double aHeight , double aWidth , double aThickness ,
double aOrientation , GR_TEXT_H_ALIGN_T aHJustify ,
2023-08-18 18:27:48 +00:00
GR_TEXT_V_ALIGN_T aVJustify , const COLOR4D & aColor )
2018-10-13 18:37:28 +00:00
{
2023-10-09 00:54:34 +00:00
m_shapes . push_back ( make_shape < IMPORTED_TEXT > ( aOrigin , aText , aHeight , aWidth , aThickness ,
aOrientation , aHJustify , aVJustify , aColor ) ) ;
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 ,
2023-08-18 18:27:48 +00:00
const VECTOR2D & aBezierControl2 , const VECTOR2D & aEnd ,
2023-10-09 03:56:13 +00:00
const IMPORTED_STROKE & aStroke )
2018-11-01 09:47:41 +00:00
{
2023-10-09 00:54:34 +00:00
m_shapes . push_back ( make_shape < IMPORTED_SPLINE > ( aStart , aBezierControl1 , aBezierControl2 , aEnd ,
aStroke ) ) ;
2018-11-01 09:47:41 +00:00
}
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 )
{
2021-12-28 22:13:54 +00:00
for ( std : : unique_ptr < IMPORTED_SHAPE > & shape : m_shapes )
2018-10-13 18:37:28 +00:00
shape - > ImportTo ( aImporter ) ;
}
2021-12-30 02:47:54 +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 ,
2023-10-09 00:54:34 +00:00
GRAPHICS_IMPORTER : : POLY_FILL_RULE aFillRule ,
2023-10-09 03:56:13 +00:00
const IMPORTED_STROKE & aStroke , bool aFilled ,
const COLOR4D & aFillColor )
2021-12-30 02:47:54 +00:00
{
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)
Fix typos in pcbnew sub-directory
Found via `codespell -q 3 -S *.po,./thirdparty,./Documentation/changelogs -L aactual,acount,aline,alocation,alog,anormal,anumber,aother,apoints,aparent,aray,ba,busses,dout,einstance,leaded,modul,ontext,ot,overide,serie,te,,tesselate,tesselator,tht`
2022-06-29 20:21:10 +00:00
// to avoid losing accuracy
2021-12-30 02:47:54 +00:00
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 ) ;
}
2023-11-04 14:09:16 +00:00
std : : vector < IMPORTED_POLYGON * > openPaths ;
std : : vector < SHAPE_LINE_CHAIN > upscaledPaths ;
2021-12-30 02:47:54 +00:00
for ( IMPORTED_POLYGON * path : aPaths )
{
2023-11-04 14:09:16 +00:00
if ( path - > Vertices ( ) . size ( ) < 3 )
{
openPaths . push_back ( path ) ;
continue ;
}
2021-12-30 02:47:54 +00:00
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 ) ) ;
}
2023-10-09 00:54:34 +00:00
aShapes . push_back (
std : : make_unique < IMPORTED_POLYGON > ( pts , aStroke , aFilled , aFillColor ) ) ;
2021-12-30 02:47:54 +00:00
}
2023-11-04 14:09:16 +00:00
for ( IMPORTED_POLYGON * openPath : openPaths )
aShapes . push_back ( std : : make_unique < IMPORTED_POLYGON > ( * openPath ) ) ;
2021-12-30 02:47:54 +00:00
}
void GRAPHICS_IMPORTER_BUFFER : : PostprocessNestedPolygons ( )
{
2023-10-09 03:56:13 +00:00
int curShapeIdx = - 1 ;
IMPORTED_STROKE lastStroke ;
bool lastFilled = false ;
COLOR4D lastFillColor = COLOR4D : : UNSPECIFIED ;
2021-12-30 02:47:54 +00:00
std : : list < std : : unique_ptr < IMPORTED_SHAPE > > newShapes ;
std : : vector < IMPORTED_POLYGON * > polypaths ;
2022-09-27 16:44:17 +00:00
for ( std : : unique_ptr < IMPORTED_SHAPE > & shape : m_shapes )
2021-12-30 02:47:54 +00:00
{
IMPORTED_POLYGON * poly = dynamic_cast < IMPORTED_POLYGON * > ( shape . get ( ) ) ;
if ( ! poly | | poly - > GetParentShapeIndex ( ) < 0 )
{
newShapes . push_back ( shape - > clone ( ) ) ;
continue ;
}
int index = poly - > GetParentShapeIndex ( ) ;
2022-09-27 16:44:17 +00:00
if ( index ! = curShapeIdx & & curShapeIdx > = 0 )
2021-12-30 02:47:54 +00:00
{
2023-10-09 00:54:34 +00:00
convertPolygon ( newShapes , polypaths , m_shapeFillRules [ curShapeIdx ] , lastStroke ,
lastFilled , lastFillColor ) ;
2021-12-30 02:47:54 +00:00
polypaths . clear ( ) ;
}
2022-09-27 16:44:17 +00:00
curShapeIdx = index ;
2023-10-09 00:54:34 +00:00
lastStroke = poly - > GetStroke ( ) ;
2023-10-09 03:56:13 +00:00
lastFilled = poly - > IsFilled ( ) ;
2023-10-09 00:54:34 +00:00
lastFillColor = poly - > GetFillColor ( ) ;
2022-09-27 16:44:17 +00:00
polypaths . push_back ( poly ) ;
}
2022-02-27 08:59:42 +00:00
2022-09-27 16:44:17 +00:00
if ( curShapeIdx > = 0 )
2023-10-09 00:54:34 +00:00
{
convertPolygon ( newShapes , polypaths , m_shapeFillRules [ curShapeIdx ] , lastStroke , lastFilled ,
lastFillColor ) ;
}
2021-12-30 02:47:54 +00:00
m_shapes . swap ( newShapes ) ;
}