diff --git a/common/common_plot_functions.cpp b/common/common_plot_functions.cpp deleted file mode 100644 index 3ce45d9afd..0000000000 --- a/common/common_plot_functions.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/** - * @file common_plot_functions.cpp - * @brief Kicad: Common plotting functions - */ - -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 1992-2017 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 -#include -#include -#include -#include -#include -#include -#include "worksheet_shape_builder.h" -#include "class_worksheet_dataitem.h" -#include - - - -wxString GetDefaultPlotExtension( PlotFormat aFormat ) -{ - switch( aFormat ) - { - case PLOT_FORMAT_DXF: - return DXF_PLOTTER::GetDefaultFileExtension(); - - case PLOT_FORMAT_POST: - return PS_PLOTTER::GetDefaultFileExtension(); - - case PLOT_FORMAT_PDF: - return PDF_PLOTTER::GetDefaultFileExtension(); - - case PLOT_FORMAT_HPGL: - return HPGL_PLOTTER::GetDefaultFileExtension(); - - case PLOT_FORMAT_GERBER: - return GERBER_PLOTTER::GetDefaultFileExtension(); - - case PLOT_FORMAT_SVG: - return SVG_PLOTTER::GetDefaultFileExtension(); - - default: - wxASSERT( false ); - return wxEmptyString; - } -} - - - -void PlotWorkSheet( PLOTTER* plotter, const TITLE_BLOCK& aTitleBlock, - const PAGE_INFO& aPageInfo, - int aSheetNumber, int aNumberOfSheets, - const wxString &aSheetDesc, const wxString &aFilename ) -{ - /* Note: Page sizes values are given in mils - */ - double iusPerMil = plotter->GetIUsPerDecimil() * 10.0; - - COLOR4D plotColor = plotter->GetColorMode() ? COLOR4D( RED ) : COLOR4D::BLACK; - plotter->SetColor( plotColor ); - WS_DRAW_ITEM_LIST drawList; - - // Print only a short filename, if aFilename is the full filename - wxFileName fn( aFilename ); - - // Prepare plot parameters - drawList.SetPenSize(PLOTTER::USE_DEFAULT_LINE_WIDTH ); - drawList.SetMilsToIUfactor( iusPerMil ); - drawList.SetSheetNumber( aSheetNumber ); - drawList.SetSheetCount( aNumberOfSheets ); - drawList.SetFileName( fn.GetFullName() ); // Print only the short filename - drawList.SetSheetName( aSheetDesc ); - - - drawList.BuildWorkSheetGraphicList( aPageInfo, - aTitleBlock, plotColor, plotColor ); - - // Draw item list - for( WS_DRAW_ITEM_BASE* item = drawList.GetFirst(); item; - item = drawList.GetNext() ) - { - plotter->SetCurrentLineWidth( PLOTTER::USE_DEFAULT_LINE_WIDTH ); - - switch( item->GetType() ) - { - case WS_DRAW_ITEM_BASE::wsg_line: - { - WS_DRAW_ITEM_LINE* line = (WS_DRAW_ITEM_LINE*) item; - plotter->SetCurrentLineWidth( line->GetPenWidth() ); - plotter->MoveTo( line->GetStart() ); - plotter->FinishTo( line->GetEnd() ); - } - break; - - case WS_DRAW_ITEM_BASE::wsg_rect: - { - WS_DRAW_ITEM_RECT* rect = (WS_DRAW_ITEM_RECT*) item; - plotter->Rect( rect->GetStart(), - rect->GetEnd(), - NO_FILL, - rect->GetPenWidth() ); - } - break; - - case WS_DRAW_ITEM_BASE::wsg_text: - { - WS_DRAW_ITEM_TEXT* text = (WS_DRAW_ITEM_TEXT*) item; - plotter->Text( text->GetTextPos(), text->GetColor(), - text->GetShownText(), text->GetTextAngle(), - text->GetTextSize(), - text->GetHorizJustify(), text->GetVertJustify(), - text->GetPenWidth(), - text->IsItalic(), text->IsBold(), - text->IsMultilineAllowed() ); - } - break; - - case WS_DRAW_ITEM_BASE::wsg_poly: - { - WS_DRAW_ITEM_POLYGON* poly = (WS_DRAW_ITEM_POLYGON*) item; - plotter->PlotPoly( poly->m_Corners, - poly->IsFilled() ? FILLED_SHAPE : NO_FILL, - poly->GetPenWidth() ); - } - break; - - case WS_DRAW_ITEM_BASE::wsg_bitmap: - { - WS_DRAW_ITEM_BITMAP* bm = (WS_DRAW_ITEM_BITMAP*) item; - - WORKSHEET_DATAITEM_BITMAP* parent = (WORKSHEET_DATAITEM_BITMAP*)bm->GetParent(); - - if( parent->m_ImageBitmap == NULL ) - break; - - parent->m_ImageBitmap->PlotImage( plotter, bm->GetPosition(), - plotColor, PLOTTER::USE_DEFAULT_LINE_WIDTH ); - } - break; - } - } -} diff --git a/common/drawtxt.cpp b/common/draw_graphic_text.cpp similarity index 100% rename from common/drawtxt.cpp rename to common/draw_graphic_text.cpp diff --git a/common/findkicadhelppath.cpp.notused b/common/findkicadhelppath.cpp.notused deleted file mode 100644 index d2d781ef57..0000000000 --- a/common/findkicadhelppath.cpp.notused +++ /dev/null @@ -1,126 +0,0 @@ - -#include -#include -#include -#include - - -/** - * Function FindKicadHelpPath - * finds the absolute path for KiCad "help" (or "help/<language>") - * Find path kicad/doc/help/xx/ or kicad/doc/help/: - * from BinDir - * else from environment variable KICAD - * else from one of s_HelpPathList - * typically c:/kicad/doc/help or /usr/share/kicad/help - * or /usr/local/share/kicad/help - * (must have kicad in path name) - * - * xx = iso639-1 language id (2 letters (generic) or 4 letters): - * fr = french (or fr_FR) - * en = English (or en_GB or en_US ...) - * de = deutch - * es = spanish - * pt = portuguese (or pt_BR ...) - * - * default = en (if not found = fr) - */ -wxString FindKicadHelpPath() -{ - bool found = false; - wxString bin_dir = Pgm().GetExecutablePath(); - - if( bin_dir.Last() == '/' ) - bin_dir.RemoveLast(); - - wxString fullPath = bin_dir.BeforeLast( '/' ); // cd .. - - fullPath += wxT( "/doc/help/" ); - - wxString localeString = Pgm().GetLocale()->GetCanonicalName(); - - wxString path_tmp = fullPath; - -#ifdef __WINDOWS__ - path_tmp.MakeLower(); -#endif - - if( path_tmp.Contains( wxT( "kicad" ) ) ) - { - if( wxDirExists( fullPath ) ) - found = true; - } - - // find kicad/help/ from environment variable KICAD - if( !found && Pgm().IsKicadEnvVariableDefined() ) - { - fullPath = Pgm().GetKicadEnvVariable() + wxT( "/doc/help/" ); - - if( wxDirExists( fullPath ) ) - found = true; - } - - if( !found ) - { - // Possibilities online help - const static wxChar* possibilities[] = { -#ifdef __WINDOWS__ - wxT( "c:/kicad/doc/help/" ), - wxT( "d:/kicad/doc/help/" ), - wxT( "c:/Program Files/kicad/doc/help/" ), - wxT( "d:/Program Files/kicad/doc/help/" ), -#else - wxT( "/usr/share/doc/kicad/help/" ), - wxT( "/usr/local/share/doc/kicad/help/" ), - wxT( "/usr/local/kicad/doc/help/" ), // default install for "universal - // tarballs" and build for a server - // (new) - wxT( "/usr/local/kicad/help/" ), // default install for "universal - // tarballs" and build for a server - // (old) -#endif - }; - - for( unsigned i=0; i - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -PLOTTER::PLOTTER( ) -{ - plotScale = 1; - defaultPenWidth = 0; - currentPenWidth = -1; // To-be-set marker - penState = 'Z'; // End-of-path idle - m_plotMirror = false; // Plot mirror option flag - m_mirrorIsHorizontal = true; - m_yaxisReversed = false; - outputFile = 0; - colorMode = false; // Starts as a BW plot - negativeMode = false; - // Temporary init to avoid not initialized vars, will be set later - m_IUsPerDecimil = 1; // will be set later to the actual value - iuPerDeviceUnit = 1; // will be set later to the actual value - m_dotMarkLength_mm = 0.1; // Dotted line parameter in mm: segment - // Dashed line parameter is 5 * dotted line mark - // Dashed line gap is 3 * dotted line mark -} - -PLOTTER::~PLOTTER() -{ - // Emergency cleanup, but closing the file is - // usually made in EndPlot(). - if( outputFile ) - fclose( outputFile ); -} - - -bool PLOTTER::OpenFile( const wxString& aFullFilename ) -{ - filename = aFullFilename; - - wxASSERT( !outputFile ); - - // Open the file in text mode (not suitable for all plotters - // but only for most of them - outputFile = wxFopen( filename, wxT( "wt" ) ); - - if( outputFile == NULL ) - return false ; - - return true; -} - - -DPOINT PLOTTER::userToDeviceCoordinates( const wxPoint& aCoordinate ) -{ - wxPoint pos = aCoordinate - plotOffset; - - double x = pos.x * plotScale; - double y = ( paperSize.y - pos.y * plotScale ); - - if( m_plotMirror ) - { - if( m_mirrorIsHorizontal ) - x = ( paperSize.x - pos.x * plotScale ); - else - y = pos.y * plotScale; - } - - if( m_yaxisReversed ) - y = paperSize.y - y; - - x *= iuPerDeviceUnit; - y *= iuPerDeviceUnit; - - return DPOINT( x, y ); -} - - -DPOINT PLOTTER::userToDeviceSize( const wxSize& size ) -{ - return DPOINT( size.x * plotScale * iuPerDeviceUnit, - size.y * plotScale * iuPerDeviceUnit ); -} - - -double PLOTTER::userToDeviceSize( double size ) const -{ - return size * plotScale * iuPerDeviceUnit; -} - - -double PLOTTER::GetDotMarkLenIU() const -{ - return userToDeviceSize( std::max( 1.0, - m_dotMarkLength_mm * 10000 / 25.4 * m_IUsPerDecimil - GetCurrentLineWidth() ) ); -} - - -double PLOTTER::GetDashMarkLenIU() const -{ - return std::max( GetDashGapLenIU(), 5.0 * GetDotMarkLenIU() ); -} - - -double PLOTTER::GetDashGapLenIU() const -{ - return 3.0 * GetDotMarkLenIU() + userToDeviceSize( 2 * GetCurrentLineWidth() ); -} - -void PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius, - FILL_T fill, int width ) -{ - wxPoint start, end; - const int delta = 50; // increment (in 0.1 degrees) to draw circles - - if( StAngle > EndAngle ) - std::swap( StAngle, EndAngle ); - - SetCurrentLineWidth( width ); - /* Please NOTE the different sign due to Y-axis flip */ - start.x = centre.x + KiROUND( cosdecideg( radius, -StAngle ) ); - start.y = centre.y + KiROUND( sindecideg( radius, -StAngle ) ); - MoveTo( start ); - for( int ii = StAngle + delta; ii < EndAngle; ii += delta ) - { - end.x = centre.x + KiROUND( cosdecideg( radius, -ii ) ); - end.y = centre.y + KiROUND( sindecideg( radius, -ii ) ); - LineTo( end ); - } - - end.x = centre.x + KiROUND( cosdecideg( radius, -EndAngle ) ); - end.y = centre.y + KiROUND( sindecideg( radius, -EndAngle ) ); - FinishTo( end ); -} - - -void PLOTTER::PlotImage(const wxImage & aImage, const wxPoint& aPos, double aScaleFactor ) -{ - wxSize size( aImage.GetWidth() * aScaleFactor, - aImage.GetHeight() * aScaleFactor ); - - wxPoint start = aPos; - start.x -= size.x / 2; - start.y -= size.y / 2; - - wxPoint end = start; - end.x += size.x; - end.y += size.y; - - Rect( start, end, NO_FILL ); -} - - -void PLOTTER::markerSquare( const wxPoint& position, int radius ) -{ - double r = KiROUND( radius / 1.4142 ); - std::vector< wxPoint > corner_list; - wxPoint corner; - corner.x = position.x + r; - corner.y = position.y + r; - corner_list.push_back( corner ); - corner.x = position.x + r; - corner.y = position.y - r; - corner_list.push_back( corner ); - corner.x = position.x - r; - corner.y = position.y - r; - corner_list.push_back( corner ); - corner.x = position.x - r; - corner.y = position.y + r; - corner_list.push_back( corner ); - corner.x = position.x + r; - corner.y = position.y + r; - corner_list.push_back( corner ); - - PlotPoly( corner_list, NO_FILL, GetCurrentLineWidth() ); -} - - -void PLOTTER::markerCircle( const wxPoint& position, int radius ) -{ - Circle( position, radius * 2, NO_FILL, GetCurrentLineWidth() ); -} - - -void PLOTTER::markerLozenge( const wxPoint& position, int radius ) -{ - std::vector< wxPoint > corner_list; - wxPoint corner; - corner.x = position.x; - corner.y = position.y + radius; - corner_list.push_back( corner ); - corner.x = position.x + radius; - corner.y = position.y, - corner_list.push_back( corner ); - corner.x = position.x; - corner.y = position.y - radius; - corner_list.push_back( corner ); - corner.x = position.x - radius; - corner.y = position.y; - corner_list.push_back( corner ); - corner.x = position.x; - corner.y = position.y + radius; - corner_list.push_back( corner ); - - PlotPoly( corner_list, NO_FILL, GetCurrentLineWidth() ); -} - - -void PLOTTER::markerHBar( const wxPoint& pos, int radius ) -{ - MoveTo( wxPoint( pos.x - radius, pos.y ) ); - FinishTo( wxPoint( pos.x + radius, pos.y ) ); -} - - -void PLOTTER::markerSlash( const wxPoint& pos, int radius ) -{ - MoveTo( wxPoint( pos.x - radius, pos.y - radius ) ); - FinishTo( wxPoint( pos.x + radius, pos.y + radius ) ); -} - - -void PLOTTER::markerBackSlash( const wxPoint& pos, int radius ) -{ - MoveTo( wxPoint( pos.x + radius, pos.y - radius ) ); - FinishTo( wxPoint( pos.x - radius, pos.y + radius ) ); -} - - -void PLOTTER::markerVBar( const wxPoint& pos, int radius ) -{ - MoveTo( wxPoint( pos.x, pos.y - radius ) ); - FinishTo( wxPoint( pos.x, pos.y + radius ) ); -} - - -void PLOTTER::Marker( const wxPoint& position, int diametre, unsigned aShapeId ) -{ - int radius = diametre / 2; - /* Marker are composed by a series of 'parts' superimposed; not every - combination make sense, obviously. Since they are used in order I - tried to keep the uglier/more complex constructions at the end. - Also I avoided the |/ |\ -/ -\ construction because they're *very* - ugly... if needed they could be added anyway... I'd like to see - a board with more than 58 drilling/slotting tools! - If Visual C++ supported the 0b literals they would be optimally - and easily encoded as an integer array. We have to do with octal */ - static const unsigned char marker_patterns[MARKER_COUNT] = { - // Bit order: O Square Lozenge - | \ / - // First choice: simple shapes - 0003, // X - 0100, // O - 0014, // + - 0040, // Sq - 0020, // Lz - // Two simple shapes - 0103, // X O - 0017, // X + - 0043, // X Sq - 0023, // X Lz - 0114, // O + - 0140, // O Sq - 0120, // O Lz - 0054, // + Sq - 0034, // + Lz - 0060, // Sq Lz - // Three simple shapes - 0117, // X O + - 0143, // X O Sq - 0123, // X O Lz - 0057, // X + Sq - 0037, // X + Lz - 0063, // X Sq Lz - 0154, // O + Sq - 0134, // O + Lz - 0074, // + Sq Lz - // Four simple shapes - 0174, // O Sq Lz + - 0163, // X O Sq Lz - 0157, // X O Sq + - 0137, // X O Lz + - 0077, // X Sq Lz + - // This draws *everything * - 0177, // X O Sq Lz + - // Here we use the single bars... so the cross is forbidden - 0110, // O - - 0104, // O | - 0101, // O / - 0050, // Sq - - 0044, // Sq | - 0041, // Sq / - 0030, // Lz - - 0024, // Lz | - 0021, // Lz / - 0150, // O Sq - - 0144, // O Sq | - 0141, // O Sq / - 0130, // O Lz - - 0124, // O Lz | - 0121, // O Lz / - 0070, // Sq Lz - - 0064, // Sq Lz | - 0061, // Sq Lz / - 0170, // O Sq Lz - - 0164, // O Sq Lz | - 0161, // O Sq Lz / - // Last resort: the backlash component (easy to confound) - 0102, // \ O - 0042, // \ Sq - 0022, // \ Lz - 0142, // \ O Sq - 0122, // \ O Lz - 0062, // \ Sq Lz - 0162 // \ O Sq Lz - }; - if( aShapeId >= MARKER_COUNT ) - { - // Fallback shape - markerCircle( position, radius ); - } - else - { - // Decode the pattern and draw the corresponding parts - unsigned char pat = marker_patterns[aShapeId]; - if( pat & 0001 ) - markerSlash( position, radius ); - if( pat & 0002 ) - markerBackSlash( position, radius ); - if( pat & 0004 ) - markerVBar( position, radius ); - if( pat & 0010 ) - markerHBar( position, radius ); - if( pat & 0020 ) - markerLozenge( position, radius ); - if( pat & 0040 ) - markerSquare( position, radius ); - if( pat & 0100 ) - markerCircle( position, radius ); - } -} - - -void PLOTTER::segmentAsOval( const wxPoint& start, const wxPoint& end, int width, - EDA_DRAW_MODE_T tracemode ) -{ - wxPoint center( (start.x + end.x) / 2, (start.y + end.y) / 2 ); - wxSize size( end.x - start.x, end.y - start.y ); - double orient; - - if( size.y == 0 ) - orient = 0; - else if( size.x == 0 ) - orient = 900; - else - orient = -ArcTangente( size.y, size.x ); - - size.x = KiROUND( EuclideanNorm( size ) ) + width; - size.y = width; - - FlashPadOval( center, size, orient, tracemode, NULL ); -} - - -void PLOTTER::sketchOval( const wxPoint& pos, const wxSize& aSize, double orient, int width ) -{ - SetCurrentLineWidth( width ); - width = currentPenWidth; - int radius, deltaxy, cx, cy; - wxSize size( aSize ); - - if( size.x > size.y ) - { - std::swap( size.x, size.y ); - orient = AddAngles( orient, 900 ); - } - - deltaxy = size.y - size.x; /* distance between centers of the oval */ - radius = ( size.x - width ) / 2; - cx = -radius; - cy = -deltaxy / 2; - RotatePoint( &cx, &cy, orient ); - MoveTo( wxPoint( cx + pos.x, cy + pos.y ) ); - cx = -radius; - cy = deltaxy / 2; - RotatePoint( &cx, &cy, orient ); - FinishTo( wxPoint( cx + pos.x, cy + pos.y ) ); - - cx = radius; - cy = -deltaxy / 2; - RotatePoint( &cx, &cy, orient ); - MoveTo( wxPoint( cx + pos.x, cy + pos.y ) ); - cx = radius; - cy = deltaxy / 2; - RotatePoint( &cx, &cy, orient ); - FinishTo( wxPoint( cx + pos.x, cy + pos.y ) ); - - cx = 0; - cy = deltaxy / 2; - RotatePoint( &cx, &cy, orient ); - Arc( wxPoint( cx + pos.x, cy + pos.y ), - orient + 1800, orient + 3600, - radius, NO_FILL ); - cx = 0; - cy = -deltaxy / 2; - RotatePoint( &cx, &cy, orient ); - Arc( wxPoint( cx + pos.x, cy + pos.y ), - orient, orient + 1800, - radius, NO_FILL ); -} - - -void PLOTTER::ThickSegment( const wxPoint& start, const wxPoint& end, int width, - EDA_DRAW_MODE_T tracemode, void* aData ) -{ - if( tracemode == FILLED ) - { - SetCurrentLineWidth( width ); - MoveTo( start ); - FinishTo( end ); - } - else - { - SetCurrentLineWidth( -1 ); - segmentAsOval( start, end, width, tracemode ); - } -} - - -void PLOTTER::ThickArc( const wxPoint& centre, double StAngle, double EndAngle, - int radius, int width, EDA_DRAW_MODE_T tracemode, void* aData ) -{ - if( tracemode == FILLED ) - Arc( centre, StAngle, EndAngle, radius, NO_FILL, width ); - else - { - SetCurrentLineWidth( -1 ); - Arc( centre, StAngle, EndAngle, - radius - ( width - currentPenWidth ) / 2, NO_FILL, -1 ); - Arc( centre, StAngle, EndAngle, - radius + ( width - currentPenWidth ) / 2, NO_FILL, -1 ); - } -} - - -void PLOTTER::ThickRect( const wxPoint& p1, const wxPoint& p2, int width, - EDA_DRAW_MODE_T tracemode, void* aData ) -{ - if( tracemode == FILLED ) - Rect( p1, p2, NO_FILL, width ); - else - { - SetCurrentLineWidth( -1 ); - wxPoint offsetp1( p1.x - (width - currentPenWidth) / 2, - p1.y - (width - currentPenWidth) / 2 ); - wxPoint offsetp2( p2.x + (width - currentPenWidth) / 2, - p2.y + (width - currentPenWidth) / 2 ); - Rect( offsetp1, offsetp2, NO_FILL, -1 ); - offsetp1.x += (width - currentPenWidth); - offsetp1.y += (width - currentPenWidth); - offsetp2.x -= (width - currentPenWidth); - offsetp2.y -= (width - currentPenWidth); - Rect( offsetp1, offsetp2, NO_FILL, -1 ); - } -} - - -void PLOTTER::ThickCircle( const wxPoint& pos, int diametre, int width, - EDA_DRAW_MODE_T tracemode, void* aData ) -{ - if( tracemode == FILLED ) - Circle( pos, diametre, NO_FILL, width ); - else - { - SetCurrentLineWidth( -1 ); - Circle( pos, diametre - width + currentPenWidth, NO_FILL, -1 ); - Circle( pos, diametre + width - currentPenWidth, NO_FILL, -1 ); - } -} - - -void PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, - int aWidth, void * aData ) -{ - std::vector< wxPoint > cornerList; - - for( int ii = 0; ii < aCornerList.PointCount(); ii++ ) - cornerList.push_back( wxPoint( aCornerList.CPoint( ii ) ) ); - - PlotPoly( cornerList , aFill, aWidth, aData ); -} - - -void PLOTTER::SetPageSettings( const PAGE_INFO& aPageSettings ) -{ - pageInfo = aPageSettings; -} diff --git a/common/plotters/common_plotDXF_functions.cpp b/common/plotters/common_plotDXF_functions.cpp deleted file mode 100644 index fe5fc8718b..0000000000 --- a/common/plotters/common_plotDXF_functions.cpp +++ /dev/null @@ -1,982 +0,0 @@ -/** - * @file common_plotDXF_functions.cpp - * @brief KiCad: Common plot DXF Routines. - */ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2017 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 -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * Oblique angle for DXF native text - * (I don't remember if 15 degrees is the ISO value... it looks nice anyway) - */ -static const double DXF_OBLIQUE_ANGLE = 15; - -/* The layer/colors palette. The acad/DXF palette is divided in 3 zones: - - - The primary colors (1 - 9) - - An HSV zone (10-250, 5 values x 2 saturations x 10 hues - - Greys (251 - 255) - - There is *no* black... the white does it on paper, usually, and - anyway it depends on the plotter configuration, since DXF colors - are meant to be logical only (they represent *both* line color and - width); later version with plot styles only complicate the matter! - - As usual, brown and magenta/purple are difficult to place since - they are actually variations of other colors. - */ -static const struct -{ - const char *name; - int color; -} dxf_layer[NBCOLORS] = -{ - { "BLACK", 7 }, // In DXF, color 7 is *both* white and black! - { "GRAY1", 251 }, - { "GRAY2", 8 }, - { "GRAY3", 9 }, - { "WHITE", 7 }, - { "LYELLOW", 51 }, - { "BLUE1", 178 }, - { "GREEN1", 98 }, - { "CYAN1", 138 }, - { "RED1", 18 }, - { "MAGENTA1", 228 }, - { "BROWN1", 58 }, - { "BLUE2", 5 }, - { "GREEN2", 3 }, - { "CYAN2", 4 }, - { "RED2", 1 }, - { "MAGENTA2", 6 }, - { "BROWN2", 54 }, - { "BLUE3", 171 }, - { "GREEN3", 91 }, - { "CYAN3", 131 }, - { "RED3", 11 }, - { "MAGENTA3", 221 }, - { "YELLOW3", 2 }, - { "BLUE4", 5 }, - { "GREEN4", 3 }, - { "CYAN4", 4 }, - { "RED4", 1 }, - { "MAGENTA4", 6 }, - { "YELLOW4", 2 } -}; - - -static const char* getDXFLineType( PlotDashType aType ) -{ - switch( aType ) - { - case PLOTDASHTYPE_SOLID: return "CONTINUOUS"; - case PLOTDASHTYPE_DASH: return "DASHED"; - case PLOTDASHTYPE_DOT: return "DOTTED"; - case PLOTDASHTYPE_DASHDOT: return "DASHDOT"; - } - - wxFAIL_MSG( "Unhandled PlotDashType" ); - return "CONTINUOUS"; -} - - -// A helper function to create a color name acceptable in DXF files -// DXF files do not use a RGB definition -static wxString getDXFColorName( COLOR4D aColor ) -{ - EDA_COLOR_T color = ColorFindNearest( int( aColor.r*255 ), - int( aColor.g*255 ), - int( aColor.b*255 ) ); - wxString cname( dxf_layer[color].name ); - return cname; -} - -/** - * Set the scale/position for the DXF plot - * The DXF engine doesn't support line widths and mirroring. The output - * coordinate system is in the first quadrant (in mm) - */ -void DXF_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil, - double aScale, bool aMirror ) -{ - plotOffset = aOffset; - plotScale = aScale; - - /* DXF paper is 'virtual' so there is no need of a paper size. - Also this way we can handle the aux origin which can be useful - (for example when aligning to a mechanical drawing) */ - paperSize.x = 0; - paperSize.y = 0; - - /* Like paper size DXF units are abstract too. Anyway there is a - * system variable (MEASUREMENT) which will be set to 1 to indicate - * metric units */ - m_IUsPerDecimil = aIusPerDecimil; - iuPerDeviceUnit = 1.0 / aIusPerDecimil; // Gives a DXF in decimils - iuPerDeviceUnit *= 0.00254; // ... now in mm - - SetDefaultLineWidth( 0 ); // No line width on DXF - m_plotMirror = false; // No mirroring on DXF - m_currentColor = COLOR4D::BLACK; -} - -/** - * Opens the DXF plot with a skeleton header - */ -bool DXF_PLOTTER::StartPlot() -{ - wxASSERT( outputFile ); - - // DXF HEADER - Boilerplate - // Defines the minimum for drawing i.e. the angle system and the - // 4 linetypes (CONTINUOUS, DOTDASH, DASHED and DOTTED) - fputs( " 0\n" - "SECTION\n" - " 2\n" - "HEADER\n" - " 9\n" - "$ANGBASE\n" - " 50\n" - "0.0\n" - " 9\n" - "$ANGDIR\n" - " 70\n" - " 1\n" - " 9\n" - "$MEASUREMENT\n" - " 70\n" - "0\n" - " 0\n" // This means 'metric units' - "ENDSEC\n" - " 0\n" - "SECTION\n" - " 2\n" - "TABLES\n" - " 0\n" - "TABLE\n" - " 2\n" - "LTYPE\n" - " 70\n" - "4\n" - " 0\n" - "LTYPE\n" - " 5\n" - "40F\n" - " 2\n" - "CONTINUOUS\n" - " 70\n" - "0\n" - " 3\n" - "Solid line\n" - " 72\n" - "65\n" - " 73\n" - "0\n" - " 40\n" - "0.0\n" - " 0\n" - "LTYPE\n" - " 5\n" - "410\n" - " 2\n" - "DASHDOT\n" - " 70\n" - "0\n" - " 3\n" - "Dash Dot ____ _ ____ _\n" - " 72\n" - "65\n" - " 73\n" - "4\n" - " 40\n" - "2.0\n" - " 49\n" - "1.25\n" - " 49\n" - "-0.25\n" - " 49\n" - "0.25\n" - " 49\n" - "-0.25\n" - " 0\n" - "LTYPE\n" - " 5\n" - "411\n" - " 2\n" - "DASHED\n" - " 70\n" - "0\n" - " 3\n" - "Dashed __ __ __ __ __\n" - " 72\n" - "65\n" - " 73\n" - "2\n" - " 40\n" - "0.75\n" - " 49\n" - "0.5\n" - " 49\n" - "-0.25\n" - " 0\n" - "LTYPE\n" - " 5\n" - "43B\n" - " 2\n" - "DOTTED\n" - " 70\n" - "0\n" - " 3\n" - "Dotted . . . .\n" - " 72\n" - "65\n" - " 73\n" - "2\n" - " 40\n" - "0.2\n" - " 49\n" - "0.0\n" - " 49\n" - "-0.2\n" - " 0\n" - "ENDTAB\n", - outputFile ); - - // Text styles table - // Defines 4 text styles, one for each bold/italic combination - fputs( " 0\n" - "TABLE\n" - " 2\n" - "STYLE\n" - " 70\n" - "4\n", outputFile ); - - static const char *style_name[4] = {"KICAD", "KICADB", "KICADI", "KICADBI"}; - for(int i = 0; i < 4; i++ ) - { - fprintf( outputFile, - " 0\n" - "STYLE\n" - " 2\n" - "%s\n" // Style name - " 70\n" - "0\n" // Standard flags - " 40\n" - "0\n" // Non-fixed height text - " 41\n" - "1\n" // Width factor (base) - " 42\n" - "1\n" // Last height (mandatory) - " 50\n" - "%g\n" // Oblique angle - " 71\n" - "0\n" // Generation flags (default) - " 3\n" - // The standard ISO font (when kicad is build with it - // the dxf text in acad matches *perfectly*) - "isocp.shx\n", // Font name (when not bigfont) - // Apply a 15 degree angle to italic text - style_name[i], i < 2 ? 0 : DXF_OBLIQUE_ANGLE ); - } - - - // Layer table - one layer per color - fprintf( outputFile, - " 0\n" - "ENDTAB\n" - " 0\n" - "TABLE\n" - " 2\n" - "LAYER\n" - " 70\n" - "%d\n", NBCOLORS ); - - /* The layer/colors palette. The acad/DXF palette is divided in 3 zones: - - - The primary colors (1 - 9) - - An HSV zone (10-250, 5 values x 2 saturations x 10 hues - - Greys (251 - 255) - */ - - for( EDA_COLOR_T i = BLACK; i < NBCOLORS; i = NextColor(i) ) - { - fprintf( outputFile, - " 0\n" - "LAYER\n" - " 2\n" - "%s\n" // Layer name - " 70\n" - "0\n" // Standard flags - " 62\n" - "%d\n" // Color number - " 6\n" - "CONTINUOUS\n",// Linetype name - dxf_layer[i].name, dxf_layer[i].color ); - } - - // End of layer table, begin entities - fputs( " 0\n" - "ENDTAB\n" - " 0\n" - "ENDSEC\n" - " 0\n" - "SECTION\n" - " 2\n" - "ENTITIES\n", outputFile ); - - return true; -} - - -bool DXF_PLOTTER::EndPlot() -{ - wxASSERT( outputFile ); - - // DXF FOOTER - fputs( " 0\n" - "ENDSEC\n" - " 0\n" - "EOF\n", outputFile ); - fclose( outputFile ); - outputFile = NULL; - - return true; -} - - -/** - * The DXF exporter handles 'colors' as layers... - */ -void DXF_PLOTTER::SetColor( COLOR4D color ) -{ - if( ( colorMode ) - || ( color == COLOR4D::BLACK ) - || ( color == COLOR4D::WHITE ) ) - { - m_currentColor = color; - } - else - m_currentColor = COLOR4D::BLACK; -} - -/** - * DXF rectangle: fill not supported - */ -void DXF_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width ) -{ - wxASSERT( outputFile ); - MoveTo( p1 ); - LineTo( wxPoint( p1.x, p2.y ) ); - LineTo( wxPoint( p2.x, p2.y ) ); - LineTo( wxPoint( p2.x, p1.y ) ); - FinishTo( wxPoint( p1.x, p1.y ) ); -} - - -/** - * DXF circle: full functionality; it even does 'fills' drawing a - * circle with a dual-arc polyline wide as the radius. - * - * I could use this trick to do other filled primitives - */ -void DXF_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_T fill, int width ) -{ - wxASSERT( outputFile ); - double radius = userToDeviceSize( diameter / 2 ); - DPOINT centre_dev = userToDeviceCoordinates( centre ); - if( radius > 0 ) - { - wxString cname = getDXFColorName( m_currentColor ); - - if( !fill ) - { - fprintf( outputFile, "0\nCIRCLE\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n", - TO_UTF8( cname ), - centre_dev.x, centre_dev.y, radius ); - } - - if( fill == FILLED_SHAPE ) - { - double r = radius*0.5; - fprintf( outputFile, "0\nPOLYLINE\n"); - fprintf( outputFile, "8\n%s\n66\n1\n70\n1\n", TO_UTF8( cname )); - fprintf( outputFile, "40\n%g\n41\n%g\n", radius, radius); - fprintf( outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname )); - fprintf( outputFile, "10\n%g\n 20\n%g\n42\n1.0\n", - centre_dev.x-r, centre_dev.y ); - fprintf( outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname )); - fprintf( outputFile, "10\n%g\n 20\n%g\n42\n1.0\n", - centre_dev.x+r, centre_dev.y ); - fprintf( outputFile, "0\nSEQEND\n"); - } - } -} - - -/** - * DXF polygon: doesn't fill it but at least it close the filled ones - * DXF does not know thick outline. - * It does not know thhick segments, therefore filled polygons with thick outline - * are converted to inflated polygon by aWidth/2 - */ -void DXF_PLOTTER::PlotPoly( const std::vector& aCornerList, - FILL_T aFill, int aWidth, void * aData ) -{ - if( aCornerList.size() <= 1 ) - return; - - unsigned last = aCornerList.size() - 1; - - // Plot outlines with lines (thickness = 0) to define the polygon - if( aWidth <= 0 ) - { - MoveTo( aCornerList[0] ); - - for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) - LineTo( aCornerList[ii] ); - - // Close polygon if 'fill' requested - if( aFill ) - { - if( aCornerList[last] != aCornerList[0] ) - LineTo( aCornerList[0] ); - } - - PenFinish(); - - return; - } - - - // if the polygon outline has thickness, and is not filled - // (i.e. is a polyline) plot outlines with thick segments - if( aWidth > 0 && !aFill ) - { - MoveTo( aCornerList[0] ); - - for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) - ThickSegment( aCornerList[ii-1], aCornerList[ii], - aWidth, FILLED, NULL ); - - return; - } - - // The polygon outline has thickness, and is filled - // Build and plot the polygon which contains the initial - // polygon and its thick outline - SHAPE_POLY_SET bufferOutline; - SHAPE_POLY_SET bufferPolybase; - const int circleToSegmentsCount = 16; - - bufferPolybase.NewOutline(); - - // enter outline as polygon: - for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) - { - TransformRoundedEndsSegmentToPolygon( bufferOutline, - aCornerList[ii-1], aCornerList[ii], circleToSegmentsCount, aWidth ); - } - - // enter the initial polygon: - for( unsigned ii = 0; ii < aCornerList.size(); ii++ ) - { - bufferPolybase.Append( aCornerList[ii] ); - } - - // Merge polygons to build the polygon which contains the initial - // polygon and its thick outline - - // create the outline which contains thick outline: - bufferPolybase.BooleanAdd( bufferOutline, SHAPE_POLY_SET::PM_FAST ); - bufferPolybase.Fracture( SHAPE_POLY_SET::PM_FAST ); - - if( bufferPolybase.OutlineCount() < 1 ) // should not happen - return; - - const SHAPE_LINE_CHAIN& path = bufferPolybase.COutline( 0 ); - - if( path.PointCount() < 2 ) // should not happen - return; - - // Now, output the final polygon to DXF file: - last = path.PointCount() - 1; - VECTOR2I point = path.CPoint( 0 ); - - wxPoint startPoint( point.x, point.y ); - MoveTo( startPoint ); - - for( int ii = 1; ii < path.PointCount(); ii++ ) - { - point = path.CPoint( ii ); - LineTo( wxPoint( point.x, point.y ) ); - } - - // Close polygon, if needed - point = path.CPoint( last ); - wxPoint endPoint( point.x, point.y ); - - if( endPoint != startPoint ) - LineTo( startPoint ); - - PenFinish(); -} - - -void DXF_PLOTTER::PenTo( const wxPoint& pos, char plume ) -{ - wxASSERT( outputFile ); - if( plume == 'Z' ) - { - return; - } - DPOINT pos_dev = userToDeviceCoordinates( pos ); - DPOINT pen_lastpos_dev = userToDeviceCoordinates( penLastpos ); - - if( penLastpos != pos && plume == 'D' ) - { - wxASSERT( m_currentLineType >= 0 && m_currentLineType < 4 ); - // DXF LINE - wxString cname = getDXFColorName( m_currentColor ); - const char *lname = getDXFLineType( (PlotDashType) m_currentLineType ); - fprintf( outputFile, "0\nLINE\n8\n%s\n6\n%s\n10\n%g\n20\n%g\n11\n%g\n21\n%g\n", - TO_UTF8( cname ), lname, - pen_lastpos_dev.x, pen_lastpos_dev.y, pos_dev.x, pos_dev.y ); - } - penLastpos = pos; -} - - -void DXF_PLOTTER::SetDash( int dashed ) -{ - wxASSERT( dashed >= 0 && dashed < 4 ); - m_currentLineType = dashed; -} - - -void DXF_PLOTTER::ThickSegment( const wxPoint& aStart, const wxPoint& aEnd, int aWidth, - EDA_DRAW_MODE_T aPlotMode, void* aData ) -{ - if( aPlotMode == SKETCH ) - { - std::vector cornerList; - SHAPE_POLY_SET outlineBuffer; - TransformOvalClearanceToPolygon( outlineBuffer, - aStart, aEnd, aWidth, 32 , 1.0 ); - const SHAPE_LINE_CHAIN& path = outlineBuffer.COutline(0 ); - - for( int jj = 0; jj < path.PointCount(); jj++ ) - cornerList.push_back( wxPoint( path.CPoint( jj ).x , path.CPoint( jj ).y ) ); - - // Ensure the polygon is closed - if( cornerList[0] != cornerList[cornerList.size() - 1] ) - cornerList.push_back( cornerList[0] ); - - PlotPoly( cornerList, NO_FILL ); - } - else - { - MoveTo( aStart ); - FinishTo( aEnd ); - } -} - -/* Plot an arc in DXF format - * Filling is not supported - */ -void DXF_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius, - FILL_T fill, int width ) -{ - wxASSERT( outputFile ); - - if( radius <= 0 ) - return; - - // In DXF, arcs are drawn CCW. - // In Kicad, arcs are CW or CCW - // If StAngle > EndAngle, it is CW. So transform it to CCW - if( StAngle > EndAngle ) - { - std::swap( StAngle, EndAngle ); - } - - DPOINT centre_dev = userToDeviceCoordinates( centre ); - double radius_dev = userToDeviceSize( radius ); - - // Emit a DXF ARC entity - wxString cname = getDXFColorName( m_currentColor ); - fprintf( outputFile, - "0\nARC\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n50\n%g\n51\n%g\n", - TO_UTF8( cname ), - centre_dev.x, centre_dev.y, radius_dev, - StAngle / 10.0, EndAngle / 10.0 ); -} - -/** - * DXF oval pad: always done in sketch mode - */ -void DXF_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, double orient, - EDA_DRAW_MODE_T trace_mode, void* aData ) -{ - wxASSERT( outputFile ); - wxSize size( aSize ); - - /* The chip is reduced to an oval tablet with size.y > size.x - * (Oval vertical orientation 0) */ - if( size.x > size.y ) - { - std::swap( size.x, size.y ); - orient = AddAngles( orient, 900 ); - } - - sketchOval( pos, size, orient, -1 ); -} - - -/** - * DXF round pad: always done in sketch mode; it could be filled but it isn't - * pretty if other kinds of pad aren't... - */ -void DXF_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre, - EDA_DRAW_MODE_T trace_mode, void* aData ) -{ - wxASSERT( outputFile ); - Circle( pos, diametre, NO_FILL ); -} - - -/** - * DXF rectangular pad: alwayd done in sketch mode - */ -void DXF_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& padsize, - double orient, EDA_DRAW_MODE_T trace_mode, void* aData ) -{ - wxASSERT( outputFile ); - wxSize size; - int ox, oy, fx, fy; - - size.x = padsize.x / 2; - size.y = padsize.y / 2; - - if( size.x < 0 ) - size.x = 0; - if( size.y < 0 ) - size.y = 0; - - // If a dimension is zero, the trace is reduced to 1 line - if( size.x == 0 ) - { - ox = pos.x; - oy = pos.y - size.y; - RotatePoint( &ox, &oy, pos.x, pos.y, orient ); - fx = pos.x; - fy = pos.y + size.y; - RotatePoint( &fx, &fy, pos.x, pos.y, orient ); - MoveTo( wxPoint( ox, oy ) ); - FinishTo( wxPoint( fx, fy ) ); - return; - } - if( size.y == 0 ) - { - ox = pos.x - size.x; - oy = pos.y; - RotatePoint( &ox, &oy, pos.x, pos.y, orient ); - fx = pos.x + size.x; - fy = pos.y; - RotatePoint( &fx, &fy, pos.x, pos.y, orient ); - MoveTo( wxPoint( ox, oy ) ); - FinishTo( wxPoint( fx, fy ) ); - return; - } - - ox = pos.x - size.x; - oy = pos.y - size.y; - RotatePoint( &ox, &oy, pos.x, pos.y, orient ); - MoveTo( wxPoint( ox, oy ) ); - - fx = pos.x - size.x; - fy = pos.y + size.y; - RotatePoint( &fx, &fy, pos.x, pos.y, orient ); - LineTo( wxPoint( fx, fy ) ); - - fx = pos.x + size.x; - fy = pos.y + size.y; - RotatePoint( &fx, &fy, pos.x, pos.y, orient ); - LineTo( wxPoint( fx, fy ) ); - - fx = pos.x + size.x; - fy = pos.y - size.y; - RotatePoint( &fx, &fy, pos.x, pos.y, orient ); - LineTo( wxPoint( fx, fy ) ); - - FinishTo( wxPoint( ox, oy ) ); -} - -void DXF_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize, - int aCornerRadius, double aOrient, - EDA_DRAW_MODE_T aTraceMode, void* aData ) -{ - SHAPE_POLY_SET outline; - const int segmentToCircleCount = 64; - TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient, - aCornerRadius, segmentToCircleCount ); - - // TransformRoundRectToPolygon creates only one convex polygon - SHAPE_LINE_CHAIN& poly = outline.Outline( 0 ); - - MoveTo( wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) ); - - for( int ii = 1; ii < poly.PointCount(); ++ii ) - LineTo( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) ); - - FinishTo( wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) ); -} - -void DXF_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize, - SHAPE_POLY_SET* aPolygons, - EDA_DRAW_MODE_T aTraceMode, void* aData ) -{ - for( int cnt = 0; cnt < aPolygons->OutlineCount(); ++cnt ) - { - SHAPE_LINE_CHAIN& poly = aPolygons->Outline( cnt ); - - MoveTo( wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) ); - - for( int ii = 1; ii < poly.PointCount(); ++ii ) - LineTo( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) ); - - FinishTo(wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) ); - } -} - - -/** - * DXF trapezoidal pad: only sketch mode is supported - */ -void DXF_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners, - double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode, void* aData ) -{ - wxASSERT( outputFile ); - wxPoint coord[4]; /* coord actual corners of a trapezoidal trace */ - - for( int ii = 0; ii < 4; ii++ ) - { - coord[ii] = aCorners[ii]; - RotatePoint( &coord[ii], aPadOrient ); - coord[ii] += aPadPos; - } - - // Plot edge: - MoveTo( coord[0] ); - LineTo( coord[1] ); - LineTo( coord[2] ); - LineTo( coord[3] ); - FinishTo( coord[0] ); -} - -/** - * Checks if a given string contains non-ASCII characters. - * FIXME: the performance of this code is really poor, but in this case it can be - * acceptable because the plot operation is not called very often. - * @param string String to check - * @return true if it contains some non-ASCII character, false if all characters are - * inside ASCII range (<=255). - */ -bool containsNonAsciiChars( const wxString& string ) -{ - for( unsigned i = 0; i < string.length(); i++ ) - { - wchar_t ch = string[i]; - if( ch > 255 ) - return true; - } - return false; -} - -void DXF_PLOTTER::Text( const wxPoint& aPos, - COLOR4D aColor, - const wxString& aText, - double aOrient, - const wxSize& aSize, - enum EDA_TEXT_HJUSTIFY_T aH_justify, - enum EDA_TEXT_VJUSTIFY_T aV_justify, - int aWidth, - bool aItalic, - bool aBold, - bool aMultilineAllowed, - void* aData ) -{ - // Fix me: see how to use DXF text mode for multiline texts - if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) ) - aMultilineAllowed = false; // the text has only one line. - - if( textAsLines || containsNonAsciiChars( aText ) || aMultilineAllowed ) - { - // output text as graphics. - // Perhaps multiline texts could be handled as DXF text entity - // but I do not want spend time about this (JPC) - PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify, - aWidth, aItalic, aBold, aMultilineAllowed ); - } - else - { - /* Emit text as a text entity. This loses formatting and shape but it's - more useful as a CAD object */ - DPOINT origin_dev = userToDeviceCoordinates( aPos ); - SetColor( aColor ); - wxString cname = getDXFColorName( m_currentColor ); - DPOINT size_dev = userToDeviceSize( aSize ); - int h_code = 0, v_code = 0; - switch( aH_justify ) - { - case GR_TEXT_HJUSTIFY_LEFT: - h_code = 0; - break; - case GR_TEXT_HJUSTIFY_CENTER: - h_code = 1; - break; - case GR_TEXT_HJUSTIFY_RIGHT: - h_code = 2; - break; - } - switch( aV_justify ) - { - case GR_TEXT_VJUSTIFY_TOP: - v_code = 3; - break; - case GR_TEXT_VJUSTIFY_CENTER: - v_code = 2; - break; - case GR_TEXT_VJUSTIFY_BOTTOM: - v_code = 1; - break; - } - - // Position, size, rotation and alignment - // The two alignment point usages is somewhat idiot (see the DXF ref) - // Anyway since we don't use the fit/aligned options, they're the same - fprintf( outputFile, - " 0\n" - "TEXT\n" - " 7\n" - "%s\n" // Text style - " 8\n" - "%s\n" // Layer name - " 10\n" - "%g\n" // First point X - " 11\n" - "%g\n" // Second point X - " 20\n" - "%g\n" // First point Y - " 21\n" - "%g\n" // Second point Y - " 40\n" - "%g\n" // Text height - " 41\n" - "%g\n" // Width factor - " 50\n" - "%g\n" // Rotation - " 51\n" - "%g\n" // Oblique angle - " 71\n" - "%d\n" // Mirror flags - " 72\n" - "%d\n" // H alignment - " 73\n" - "%d\n", // V alignment - aBold ? (aItalic ? "KICADBI" : "KICADB") - : (aItalic ? "KICADI" : "KICAD"), - TO_UTF8( cname ), - origin_dev.x, origin_dev.x, - origin_dev.y, origin_dev.y, - size_dev.y, fabs( size_dev.x / size_dev.y ), - aOrient / 10.0, - aItalic ? DXF_OBLIQUE_ANGLE : 0, - size_dev.x < 0 ? 2 : 0, // X mirror flag - h_code, v_code ); - - /* There are two issue in emitting the text: - - Our overline character (~) must be converted to the appropriate - control sequence %%O or %%o - - Text encoding in DXF is more or less unspecified since depends on - the DXF declared version, the acad version reading it *and* some - system variables to be put in the header handled only by newer acads - Also before R15 unicode simply is not supported (you need to use - bigfonts which are a massive PITA). Common denominator solution: - use Latin1 (and however someone could choke on it, anyway). Sorry - for the extended latin people. If somewant want to try fixing this - recent version seems to use UTF-8 (and not UCS2 like the rest of - Windows) - - XXX Actually there is a *third* issue: older DXF formats are limited - to 255 bytes records (it was later raised to 2048); since I'm lazy - and text so long is not probable I just don't implement this rule. - If someone is interested in fixing this, you have to emit the first - partial lines with group code 3 (max 250 bytes each) and then finish - with a group code 1 (less than 250 bytes). The DXF refs explains it - in no more details... - */ - - bool overlining = false; - fputs( " 1\n", outputFile ); - for( unsigned i = 0; i < aText.length(); i++ ) - { - /* Here I do a bad thing: writing the output one byte at a time! - but today I'm lazy and I have no idea on how to coerce a Unicode - wxString to spit out latin1 encoded text ... - - Atleast stdio is *supposed* to do output buffering, so there is - hope is not too slow */ - wchar_t ch = aText[i]; - if( ch > 255 ) - { - // I can't encode this... - putc( '?', outputFile ); - } - else - { - if( ch == '~' ) - { - // Handle the overline toggle - fputs( overlining ? "%%o" : "%%O", outputFile ); - overlining = !overlining; - } - else - { - putc( ch, outputFile ); - } - } - } - putc( '\n', outputFile ); - } -} - diff --git a/common/plotters/common_plotGERBER_functions.cpp b/common/plotters/common_plotGERBER_functions.cpp deleted file mode 100644 index a8f794f214..0000000000 --- a/common/plotters/common_plotGERBER_functions.cpp +++ /dev/null @@ -1,974 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 2017 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 - */ - -/** - * @file common_plotGERBER_functions.cpp - * @brief Common GERBER plot routines. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - - -GERBER_PLOTTER::GERBER_PLOTTER() -{ - workFile = NULL; - finalFile = NULL; - currentAperture = apertures.end(); - m_apertureAttribute = 0; - - // number of digits after the point (number of digits of the mantissa - // Be carefull: the Gerber coordinates are stored in an integer - // so 6 digits (inches) or 5 digits (mm) is a good value - // To avoid overflow, 7 digits (inches) or 6 digits is a max. - // with lower values than 6 digits (inches) or 5 digits (mm), - // Creating self-intersecting polygons from non-intersecting polygons - // happen easily. - m_gerberUnitInch = false; - m_gerberUnitFmt = 6; - m_useX2Attributes = false; - m_useNetAttributes = true; -} - - -void GERBER_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil, - double aScale, bool aMirror ) -{ - wxASSERT( aMirror == false ); - m_plotMirror = false; - plotOffset = aOffset; - wxASSERT( aScale == 1 ); // aScale parameter is not used in Gerber - plotScale = 1; // Plot scale is *always* 1.0 - - m_IUsPerDecimil = aIusPerDecimil; - // gives now a default value to iuPerDeviceUnit (because the units of the caller is now known) - // which could be modified later by calling SetGerberCoordinatesFormat() - iuPerDeviceUnit = pow( 10.0, m_gerberUnitFmt ) / ( m_IUsPerDecimil * 10000.0 ); - - // We don't handle the filmbox, and it's more useful to keep the - // origin at the origin - paperSize.x = 0; - paperSize.y = 0; - SetDefaultLineWidth( 100 * aIusPerDecimil ); // Arbitrary default -} - - -void GERBER_PLOTTER::SetGerberCoordinatesFormat( int aResolution, bool aUseInches ) -{ - m_gerberUnitInch = aUseInches; - m_gerberUnitFmt = aResolution; - - iuPerDeviceUnit = pow( 10.0, m_gerberUnitFmt ) / ( m_IUsPerDecimil * 10000.0 ); - - if( ! m_gerberUnitInch ) - iuPerDeviceUnit *= 25.4; // gerber output in mm -} - - -void GERBER_PLOTTER::emitDcode( const DPOINT& pt, int dcode ) -{ - - fprintf( outputFile, "X%dY%dD%02d*\n", - KiROUND( pt.x ), KiROUND( pt.y ), dcode ); -} - - -void GERBER_PLOTTER::clearNetAttribute() -{ - // disable a Gerber net attribute (exists only in X2 with net attributes mode). - if( m_objectAttributesDictionnary.empty() ) // No net attribute or not X2 mode - return; - - // Remove all net attributes from object attributes dictionnary - fputs( "%TD*%\n", outputFile ); - - m_objectAttributesDictionnary.clear(); -} - - -void GERBER_PLOTTER::StartBlock( void* aData ) -{ - // Currently, it is the same as EndBlock(): clear all aperture net attributes - EndBlock( aData ); -} - - -void GERBER_PLOTTER::EndBlock( void* aData ) -{ - // Remove all net attributes from object attributes dictionnary - clearNetAttribute(); -} - - -void GERBER_PLOTTER::formatNetAttribute( GBR_NETLIST_METADATA* aData ) -{ - // print a Gerber net attribute record. - // it is added to the object attributes dictionnary - // On file, only modified or new attributes are printed. - if( aData == NULL || !m_useX2Attributes || !m_useNetAttributes ) - return; - - bool clearDict; - std::string short_attribute_string; - - if( !FormatNetAttribute( short_attribute_string, m_objectAttributesDictionnary, - aData, clearDict ) ) - return; - - if( clearDict ) - clearNetAttribute(); - - if( !short_attribute_string.empty() ) - fputs( short_attribute_string.c_str(), outputFile ); -} - - -bool GERBER_PLOTTER::StartPlot() -{ - wxASSERT( outputFile ); - - finalFile = outputFile; // the actual gerber file will be created later - - // Create a temporary filename to store gerber file - // note tmpfile() does not work under Vista and W7 in user mode - m_workFilename = filename + wxT(".tmp"); - workFile = wxFopen( m_workFilename, wxT( "wt" )); - outputFile = workFile; - wxASSERT( outputFile ); - - if( outputFile == NULL ) - return false; - - for( unsigned ii = 0; ii < m_headerExtraLines.GetCount(); ii++ ) - { - if( ! m_headerExtraLines[ii].IsEmpty() ) - fprintf( outputFile, "%s\n", TO_UTF8( m_headerExtraLines[ii] ) ); - } - - // Set coordinate format to 3.6 or 4.5 absolute, leading zero omitted - // the number of digits for the integer part of coordintes is needed - // in gerber format, but is not very important when omitting leading zeros - // It is fixed here to 3 (inch) or 4 (mm), but is not actually used - int leadingDigitCount = m_gerberUnitInch ? 3 : 4; - - fprintf( outputFile, "%%FSLAX%d%dY%d%d*%%\n", - leadingDigitCount, m_gerberUnitFmt, - leadingDigitCount, m_gerberUnitFmt ); - fprintf( outputFile, - "G04 Gerber Fmt %d.%d, Leading zero omitted, Abs format (unit %s)*\n", - leadingDigitCount, m_gerberUnitFmt, - m_gerberUnitInch ? "inch" : "mm" ); - - wxString Title = creator + wxT( " " ) + GetBuildVersion(); - fprintf( outputFile, "G04 Created by KiCad (%s) date %s*\n", - TO_UTF8( Title ), TO_UTF8( DateAndTime() ) ); - - /* Mass parameter: unit = INCHES/MM */ - if( m_gerberUnitInch ) - fputs( "%MOIN*%\n", outputFile ); - else - fputs( "%MOMM*%\n", outputFile ); - - // Be sure the usual dark polarity is selected: - fputs( "%LPD*%\n", outputFile ); - - // Specify linear interpol (G01): - fputs( "G01*\n", outputFile ); - - fputs( "G04 APERTURE LIST*\n", outputFile ); - - return true; -} - - -bool GERBER_PLOTTER::EndPlot() -{ - char line[1024]; - wxString msg; - - wxASSERT( outputFile ); - - /* Outfile is actually a temporary file i.e. workFile */ - fputs( "M02*\n", outputFile ); - fflush( outputFile ); - - fclose( workFile ); - workFile = wxFopen( m_workFilename, wxT( "rt" )); - wxASSERT( workFile ); - outputFile = finalFile; - - // Placement of apertures in RS274X - while( fgets( line, 1024, workFile ) ) - { - fputs( line, outputFile ); - - if( strcmp( strtok( line, "\n\r" ), "G04 APERTURE LIST*" ) == 0 ) - { - writeApertureList(); - fputs( "G04 APERTURE END LIST*\n", outputFile ); - } - } - - fclose( workFile ); - fclose( finalFile ); - ::wxRemoveFile( m_workFilename ); - outputFile = 0; - - return true; -} - - -void GERBER_PLOTTER::SetDefaultLineWidth( int width ) -{ - defaultPenWidth = width; - currentAperture = apertures.end(); -} - - -void GERBER_PLOTTER::SetCurrentLineWidth( int width, void* aData ) -{ - if( width == DO_NOT_SET_LINE_WIDTH ) - return; - - int pen_width; - - if( width > 0 ) - pen_width = width; - else - pen_width = defaultPenWidth; - - GBR_METADATA* gbr_metadata = static_cast( aData ); - int aperture_attribute = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; - - selectAperture( wxSize( pen_width, pen_width ), APERTURE::Plotting, aperture_attribute ); - currentPenWidth = pen_width; -} - - -std::vector::iterator GERBER_PLOTTER::getAperture( const wxSize& aSize, - APERTURE::APERTURE_TYPE aType, int aApertureAttribute ) -{ - int last_D_code = 9; - - // Search an existing aperture - std::vector::iterator tool = apertures.begin(); - - while( tool != apertures.end() ) - { - last_D_code = tool->m_DCode; - - if( (tool->m_Type == aType) && (tool->m_Size == aSize) && (tool->m_ApertureAttribute == aApertureAttribute) ) - return tool; - - ++tool; - } - - // Allocate a new aperture - APERTURE new_tool; - new_tool.m_Size = aSize; - new_tool.m_Type = aType; - new_tool.m_DCode = last_D_code + 1; - new_tool.m_ApertureAttribute = aApertureAttribute; - - apertures.push_back( new_tool ); - - return apertures.end() - 1; -} - - -void GERBER_PLOTTER::selectAperture( const wxSize& aSize, - APERTURE::APERTURE_TYPE aType, - int aApertureAttribute ) -{ - bool change = ( currentAperture == apertures.end() ) || - ( currentAperture->m_Type != aType ) || - ( currentAperture->m_Size != aSize ); - - if( !m_useX2Attributes || !m_useNetAttributes ) - aApertureAttribute = 0; - else - change = change || ( currentAperture->m_ApertureAttribute != aApertureAttribute ); - - if( change ) - { - // Pick an existing aperture or create a new one - currentAperture = getAperture( aSize, aType, aApertureAttribute ); - fprintf( outputFile, "D%d*\n", currentAperture->m_DCode ); - } -} - - -void GERBER_PLOTTER::writeApertureList() -{ - wxASSERT( outputFile ); - char cbuf[1024]; - - // Init - for( std::vector::iterator tool = apertures.begin(); - tool != apertures.end(); ++tool ) - { - // apertude sizes are in inch or mm, regardless the - // coordinates format - double fscale = 0.0001 * plotScale / m_IUsPerDecimil; // inches - - if(! m_gerberUnitInch ) - fscale *= 25.4; // size in mm - - int attribute = tool->m_ApertureAttribute; - - if( attribute != m_apertureAttribute ) - fputs( GBR_APERTURE_METADATA::FormatAttribute( - (GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB) attribute ).c_str(), outputFile ); - - char* text = cbuf + sprintf( cbuf, "%%ADD%d", tool->m_DCode ); - - /* Please note: the Gerber specs for mass parameters say that - exponential syntax is *not* allowed and the decimal point should - also be always inserted. So the %g format is ruled out, but %f is fine - (the # modifier forces the decimal point). Sadly the %f formatter - can't remove trailing zeros but thats not a problem, since nothing - forbid it (the file is only slightly longer) */ - - switch( tool->m_Type ) - { - case APERTURE::Circle: - sprintf( text, "C,%#f*%%\n", tool->m_Size.x * fscale ); - break; - - case APERTURE::Rect: - sprintf( text, "R,%#fX%#f*%%\n", - tool->m_Size.x * fscale, - tool->m_Size.y * fscale ); - break; - - case APERTURE::Plotting: - sprintf( text, "C,%#f*%%\n", tool->m_Size.x * fscale ); - break; - - case APERTURE::Oval: - sprintf( text, "O,%#fX%#f*%%\n", - tool->m_Size.x * fscale, - tool->m_Size.y * fscale ); - break; - } - - fputs( cbuf, outputFile ); - - m_apertureAttribute = attribute; - - // Currently reset the aperture attribute. Perhaps a better optimization - // is to store the last attribute - if( attribute ) - { - fputs( "%TD*%\n", outputFile ); - m_apertureAttribute = 0; - } - - } -} - - -void GERBER_PLOTTER::PenTo( const wxPoint& aPos, char plume ) -{ - wxASSERT( outputFile ); - DPOINT pos_dev = userToDeviceCoordinates( aPos ); - - switch( plume ) - { - case 'Z': - break; - - case 'U': - emitDcode( pos_dev, 2 ); - break; - - case 'D': - emitDcode( pos_dev, 1 ); - } - - penState = plume; -} - - -void GERBER_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width ) -{ - std::vector< wxPoint > cornerList; - - // Build corners list - cornerList.push_back( p1 ); - wxPoint corner(p1.x, p2.y); - cornerList.push_back( corner ); - cornerList.push_back( p2 ); - corner.x = p2.x; - corner.y = p1.y; - cornerList.push_back( corner ); - cornerList.push_back( p1 ); - - PlotPoly( cornerList, fill, width ); -} - - -void GERBER_PLOTTER::Circle( const wxPoint& aCenter, int aDiameter, FILL_T aFill, int aWidth ) -{ - Arc( aCenter, 0, 3600, aDiameter / 2, aFill, aWidth ); -} - - -void GERBER_PLOTTER::Arc( const wxPoint& aCenter, double aStAngle, double aEndAngle, - int aRadius, FILL_T aFill, int aWidth ) -{ - SetCurrentLineWidth( aWidth ); - - wxPoint start, end; - start.x = aCenter.x + KiROUND( cosdecideg( aRadius, aStAngle ) ); - start.y = aCenter.y - KiROUND( sindecideg( aRadius, aStAngle ) ); - MoveTo( start ); - end.x = aCenter.x + KiROUND( cosdecideg( aRadius, aEndAngle ) ); - end.y = aCenter.y - KiROUND( sindecideg( aRadius, aEndAngle ) ); - DPOINT devEnd = userToDeviceCoordinates( end ); - DPOINT devCenter = userToDeviceCoordinates( aCenter ) - userToDeviceCoordinates( start ); - - fprintf( outputFile, "G75*\n" ); // Multiquadrant mode - - if( aStAngle < aEndAngle ) - fprintf( outputFile, "G03" ); - else - fprintf( outputFile, "G02" ); - - fprintf( outputFile, "X%dY%dI%dJ%dD01*\n", - KiROUND( devEnd.x ), KiROUND( devEnd.y ), - KiROUND( devCenter.x ), KiROUND( devCenter.y ) ); - fprintf( outputFile, "G01*\n" ); // Back to linear interp. -} - - -void GERBER_PLOTTER:: PlotPoly( const std::vector< wxPoint >& aCornerList, - FILL_T aFill, int aWidth, void * aData ) -{ - if( aCornerList.size() <= 1 ) - return; - - // Gerber format does not know filled polygons with thick outline - // Therefore, to plot a filled polygon with outline having a thickness, - // one should plot outline as thick segments - GBR_METADATA* gbr_metadata = static_cast( aData ); - - SetCurrentLineWidth( aWidth, gbr_metadata ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - if( aFill ) - { - fputs( "G36*\n", outputFile ); - - MoveTo( aCornerList[0] ); - - for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) - LineTo( aCornerList[ii] ); - - FinishTo( aCornerList[0] ); - fputs( "G37*\n", outputFile ); - } - - if( aWidth > 0 ) - { - MoveTo( aCornerList[0] ); - - for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) - LineTo( aCornerList[ii] ); - - // Ensure the thick outline is closed for filled polygons - // (if not filled, could be only a polyline) - if( aFill && ( aCornerList[aCornerList.size()-1] != aCornerList[0] ) ) - LineTo( aCornerList[0] ); - - PenFinish(); - } -} - - -void GERBER_PLOTTER::ThickSegment( const wxPoint& start, const wxPoint& end, int width, - EDA_DRAW_MODE_T tracemode, void* aData ) -{ - if( tracemode == FILLED ) - { - GBR_METADATA *gbr_metadata = static_cast( aData ); - SetCurrentLineWidth( width, gbr_metadata ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - MoveTo( start ); - FinishTo( end ); - } - else - { - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); - segmentAsOval( start, end, width, tracemode ); - } -} - -void GERBER_PLOTTER::ThickArc( const wxPoint& centre, double StAngle, double EndAngle, - int radius, int width, EDA_DRAW_MODE_T tracemode, void* aData ) -{ - GBR_METADATA *gbr_metadata = static_cast( aData ); - SetCurrentLineWidth( width, gbr_metadata ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - if( tracemode == FILLED ) - Arc( centre, StAngle, EndAngle, radius, NO_FILL, DO_NOT_SET_LINE_WIDTH ); - else - { - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); - Arc( centre, StAngle, EndAngle, - radius - ( width - currentPenWidth ) / 2, - NO_FILL, DO_NOT_SET_LINE_WIDTH ); - Arc( centre, StAngle, EndAngle, - radius + ( width - currentPenWidth ) / 2, NO_FILL, - DO_NOT_SET_LINE_WIDTH ); - } -} - - -void GERBER_PLOTTER::ThickRect( const wxPoint& p1, const wxPoint& p2, int width, - EDA_DRAW_MODE_T tracemode, void* aData ) -{ - GBR_METADATA *gbr_metadata = static_cast( aData ); - SetCurrentLineWidth( width, gbr_metadata ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - if( tracemode == FILLED ) - Rect( p1, p2, NO_FILL, DO_NOT_SET_LINE_WIDTH ); - else - { - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); - wxPoint offsetp1( p1.x - (width - currentPenWidth) / 2, - p1.y - (width - currentPenWidth) / 2 ); - wxPoint offsetp2( p2.x + (width - currentPenWidth) / 2, - p2.y + (width - currentPenWidth) / 2 ); - Rect( offsetp1, offsetp2, NO_FILL, -1 ); - offsetp1.x += (width - currentPenWidth); - offsetp1.y += (width - currentPenWidth); - offsetp2.x -= (width - currentPenWidth); - offsetp2.y -= (width - currentPenWidth); - Rect( offsetp1, offsetp2, NO_FILL, DO_NOT_SET_LINE_WIDTH ); - } -} - - -void GERBER_PLOTTER::ThickCircle( const wxPoint& pos, int diametre, int width, - EDA_DRAW_MODE_T tracemode, void* aData ) -{ - GBR_METADATA *gbr_metadata = static_cast( aData ); - SetCurrentLineWidth( width, gbr_metadata ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - if( tracemode == FILLED ) - Circle( pos, diametre, NO_FILL, DO_NOT_SET_LINE_WIDTH ); - else - { - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH, gbr_metadata ); - Circle( pos, diametre - (width - currentPenWidth), - NO_FILL, DO_NOT_SET_LINE_WIDTH ); - Circle( pos, diametre + (width - currentPenWidth), - NO_FILL, DO_NOT_SET_LINE_WIDTH ); - } -} - - -void GERBER_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre, EDA_DRAW_MODE_T trace_mode, void* aData ) -{ - wxSize size( diametre, diametre ); - GBR_METADATA* gbr_metadata = static_cast( aData ); - - if( trace_mode == SKETCH ) - { - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH, gbr_metadata ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - Circle( pos, diametre - currentPenWidth, NO_FILL, DO_NOT_SET_LINE_WIDTH ); - } - else - { - DPOINT pos_dev = userToDeviceCoordinates( pos ); - - int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; - selectAperture( size, APERTURE::Circle, aperture_attrib ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - emitDcode( pos_dev, 3 ); - } -} - - -void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, double orient, - EDA_DRAW_MODE_T trace_mode, void* aData ) -{ - wxASSERT( outputFile ); - int x0, y0, x1, y1, delta; - wxSize size( aSize ); - GBR_METADATA* gbr_metadata = static_cast( aData ); - - /* Plot a flashed shape. */ - if( ( orient == 0 || orient == 900 || orient == 1800 || orient == 2700 ) - && trace_mode == FILLED ) - { - if( orient == 900 || orient == 2700 ) /* orientation turned 90 deg. */ - std::swap( size.x, size.y ); - - DPOINT pos_dev = userToDeviceCoordinates( pos ); - int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; - selectAperture( size, APERTURE::Oval, aperture_attrib ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - emitDcode( pos_dev, 3 ); - } - else /* Plot pad as a segment. */ - { - if( size.x > size.y ) - { - std::swap( size.x, size.y ); - - if( orient < 2700 ) - orient += 900; - else - orient -= 2700; - } - - if( trace_mode == FILLED ) - { - // TODO: use an aperture macro to declare the rotated pad - // - - // Flash a pad anchor, if a netlist attribute is set - if( aData ) - FlashPadCircle( pos, size.x, trace_mode, aData ); - - // The pad is reduced to an segment with dy > dx - delta = size.y - size.x; - x0 = 0; - y0 = -delta / 2; - x1 = 0; - y1 = delta / 2; - RotatePoint( &x0, &y0, orient ); - RotatePoint( &x1, &y1, orient ); - GBR_METADATA metadata; - - if( gbr_metadata ) - { - metadata = *gbr_metadata; - - // If the pad is drawn on a copper layer, - // set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR - if( metadata.IsCopper() ) - metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR ); - - // Clear .P attribute, only allowed for flashed items - wxString attrname( ".P" ); - metadata.m_NetlistMetadata.ClearAttribute( &attrname ); - } - - ThickSegment( wxPoint( pos.x + x0, pos.y + y0 ), - wxPoint( pos.x + x1, pos.y + y1 ), - size.x, trace_mode, &metadata ); - } - else - { - sketchOval( pos, size, orient, -1 ); - } - } -} - - -void GERBER_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& aSize, - double orient, EDA_DRAW_MODE_T trace_mode, void* aData ) - -{ - wxASSERT( outputFile ); - wxSize size( aSize ); - GBR_METADATA* gbr_metadata = static_cast( aData ); - - // Plot as an aperture flash - switch( int( orient ) ) - { - case 900: - case 2700: // rotation of 90 degrees or 270 swaps sizes - std::swap( size.x, size.y ); - - // Pass through - case 0: - case 1800: - if( trace_mode == SKETCH ) - { - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH, gbr_metadata ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - Rect( wxPoint( pos.x - (size.x - currentPenWidth) / 2, - pos.y - (size.y - currentPenWidth) / 2 ), - wxPoint( pos.x + (size.x - currentPenWidth) / 2, - pos.y + (size.y - currentPenWidth) / 2 ), - NO_FILL ); - } - else - { - DPOINT pos_dev = userToDeviceCoordinates( pos ); - int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0; - selectAperture( size, APERTURE::Rect, aperture_attrib ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - emitDcode( pos_dev, 3 ); - } - break; - - default: // plot pad shape as polygon - { - // XXX to do: use an aperture macro to declare the rotated pad - wxPoint coord[4]; - // coord[0] is assumed the lower left - // coord[1] is assumed the upper left - // coord[2] is assumed the upper right - // coord[3] is assumed the lower right - - /* Trace the outline. */ - coord[0].x = -size.x/2; // lower left - coord[0].y = size.y/2; - coord[1].x = -size.x/2; // upper left - coord[1].y = -size.y/2; - coord[2].x = size.x/2; // upper right - coord[2].y = -size.y/2; - coord[3].x = size.x/2; // lower right - coord[3].y = size.y/2; - - FlashPadTrapez( pos, coord, orient, trace_mode, aData ); - } - break; - } -} - -void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize, - int aCornerRadius, double aOrient, - EDA_DRAW_MODE_T aTraceMode, void* aData ) - -{ - // Currently, a Pad RoundRect is plotted as polygon. - // TODO: use Aperture macro and flash it - SHAPE_POLY_SET outline; - const int segmentToCircleCount = 64; - TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient, - aCornerRadius, segmentToCircleCount ); - - std::vector< wxPoint > cornerList; - cornerList.reserve( segmentToCircleCount + 5 ); - // TransformRoundRectToPolygon creates only one convex polygon - SHAPE_LINE_CHAIN& poly = outline.Outline( 0 ); - - for( int ii = 0; ii < poly.PointCount(); ++ii ) - cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) ); - - // Close polygon - cornerList.push_back( cornerList[0] ); - - GBR_METADATA gbr_metadata; - - if( aData ) - { - gbr_metadata = *static_cast( aData ); - // If the pad is drawn on a copper layer, - // set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR - if( gbr_metadata.IsCopper() ) - gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR ); - - wxString attrname( ".P" ); - gbr_metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers - } - - PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILLED_SHAPE : NO_FILL, USE_DEFAULT_LINE_WIDTH, &gbr_metadata ); - - // Now, flash a pad anchor, if a netlist attribute is set - // (remove me when a Aperture macro will be used) - if( aData && aTraceMode == FILLED ) - { - int diameter = std::min( aSize.x, aSize.y ); - FlashPadCircle( aPadPos, diameter, aTraceMode , aData ); - } -} - -void GERBER_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize, - SHAPE_POLY_SET* aPolygons, - EDA_DRAW_MODE_T aTraceMode, void* aData ) - -{ - // A Pad custom is plotted as polygon. - - // A flashed circle @aPadPos is added (anchor pad) - // However, because the anchor pad can be circle or rect, we use only - // a circle not bigger than the rect. - // the main purpose is to print a flashed DCode as pad anchor - FlashPadCircle( aPadPos, std::min( aSize.x, aSize.y ), aTraceMode, aData ); - GBR_METADATA gbr_metadata; - - if( aData ) - { - gbr_metadata = *static_cast( aData ); - // If the pad is drawn on a copper layer, - // set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR - if( gbr_metadata.IsCopper() ) - gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR ); - - wxString attrname( ".P" ); - gbr_metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers - } - - std::vector< wxPoint > cornerList; - - for( int cnt = 0; cnt < aPolygons->OutlineCount(); ++cnt ) - { - SHAPE_LINE_CHAIN& poly = aPolygons->Outline( cnt ); - cornerList.clear(); - - for( int ii = 0; ii < poly.PointCount(); ++ii ) - cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) ); - - // Close polygon - cornerList.push_back( cornerList[0] ); - - PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILLED_SHAPE : NO_FILL, USE_DEFAULT_LINE_WIDTH, &gbr_metadata ); - } -} - - -void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCorners, - double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode, void* aData ) - -{ - // Currently, a Pad Trapezoid is plotted as polygon. - // TODO: use Aperture macro and flash it - - // polygon corners list - std::vector< wxPoint > cornerList; - - for( int ii = 0; ii < 4; ii++ ) - cornerList.push_back( aCorners[ii] ); - - // Now, flash a pad anchor, if a netlist attribute is set - // (remove me when a Aperture macro will be used) - if( aData && (aTrace_Mode==FILLED) ) - { - // Calculate the radius of the circle inside the shape - // It is the smaller dist from shape pos to edges - int radius = INT_MAX; - - for( unsigned ii = 0, jj = cornerList.size()-1; ii < cornerList.size(); - jj = ii, ii++ ) - { - SEG segment( aCorners[ii], aCorners[jj] ); - int dist = segment.LineDistance( VECTOR2I( 0, 0) ); - radius = std::min( radius, dist ); - } - - FlashPadCircle( aPadPos, radius*2, aTrace_Mode, aData ); - } - - // Draw the polygon and fill the interior as required - for( unsigned ii = 0; ii < 4; ii++ ) - { - RotatePoint( &cornerList[ii], aPadOrient ); - cornerList[ii] += aPadPos; - } - - // Close the polygon - cornerList.push_back( cornerList[0] ); - GBR_METADATA* gbr_metadata = static_cast( aData ); - - GBR_METADATA metadata; - - if( gbr_metadata ) - { - metadata = *gbr_metadata; - // If the pad is drawn on a copper layer, - // set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR - if( metadata.IsCopper() ) - metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR ); - - wxString attrname( ".P" ); - metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers - } - - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH, &metadata ); - PlotPoly( cornerList, aTrace_Mode==FILLED ? FILLED_SHAPE : NO_FILL, USE_DEFAULT_LINE_WIDTH, &metadata ); -} - - -void GERBER_PLOTTER::Text( const wxPoint& aPos, const COLOR4D aColor, - const wxString& aText, double aOrient, const wxSize& aSize, - enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, - int aWidth, bool aItalic, bool aBold, bool aMultilineAllowed, - void* aData ) -{ - GBR_METADATA* gbr_metadata = static_cast( aData ); - - if( gbr_metadata ) - formatNetAttribute( &gbr_metadata->m_NetlistMetadata ); - - PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, - aH_justify, aV_justify, aWidth, aItalic, aBold, aMultilineAllowed, aData ); -} - - -void GERBER_PLOTTER::SetLayerPolarity( bool aPositive ) -{ - if( aPositive ) - fprintf( outputFile, "%%LPD*%%\n" ); - else - fprintf( outputFile, "%%LPC*%%\n" ); -} diff --git a/common/plotters/common_plotHPGL_functions.cpp b/common/plotters/common_plotHPGL_functions.cpp deleted file mode 100644 index d211a04576..0000000000 --- a/common/plotters/common_plotHPGL_functions.cpp +++ /dev/null @@ -1,693 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 2017 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 - */ - -/** - * @file common_plotHPGL_functions.cpp - * @brief KiCad: Common plot HPGL Routines - * Since this plot engine is mostly intended for import in external programs, - * sadly HPGL/2 isn't supported a lot... some of the primitives use overlapped - * strokes to fill the shape - */ - -/* Some HPGL commands: - * Note: the HPGL unit is 25 micrometers - * All commands MUST be terminated by a semi-colon or a linefeed. - * Spaces can NOT be substituted for required commas in the syntax of a command. - * - * - * AA (Arc Absolute): Angle is a floating point # (requires non integer value) - * Draws an arc with the center at (X,Y). - * A positive angle creates a counter-clockwise arc. - * If the chord angle is specified, - * this will be the number of degrees used for stepping around the arc. - * If no value is given then a default value of five degrees is used. - * AA x, y, a {,b}; - * - * AR (Arc Relative): - * AR Dx, Dy, a {, b}; - * - * CA (Alternate Character Set): - * CA {n}; - * - * CI (Circle): - * CI r {,b}; - * - * CP (Character Plot): - * CP {h, v}; - * h [-127.9999 .. 127.9999] Anzahl der Zeichen horizontal - * v [-127.9999 .. 127.9999] Anzahl der Zeichen vertikal - * - * CS (Standard Character Set): - * CS {n}; - * - * DR (Relative Direction for Label Text): - * DR s, a; - * - * DI (Absolute Direction for Label Text): - * DI {s, a}; - * - * DT (Define Terminator - this character becomes unavailable except to terminate a label string. - * Default is ^C control-C): - * DT t; - * - * EA (rEctangle Absolute - Unfilled, from current position to diagonal x,y): - * EA x, y; - * - * ER (rEctangle Relative - Unfilled, from current position to diagonal x,y): - * ER x,y; - * - * FT (Fill Type): - * FT {s {,l {a}}}; - * - * IM (Input Mask): - * IM {f}; - * - * IN (Initialize): This command instructs the controller to begin processing the HPGL plot file. - * Without this, the commands in the file are received but never executed. - * If multiple IN s are found during execution of the file, - * the controller performs a Pause/Cancel operation. - * All motion from the previous job, yet to be executed, is lost, - * and the new information is executed. - * IN; - * - * IP Input P1 and P2: - * IP {P1x, P1y {, P2x, P2y}}; - * - * IW (Input Window): - * IW {XUL, YUL, XOR, YOR}; - * - * LB (Label): - * LB c1 .. cn t; - * - * PA (Plot Absolute): Moves to an absolute HPGL position and sets absolute mode for - * future PU and PD commands. If no arguments follow the command, - * only absolute mode is set. - * PA {x1, y1 {{PU|PD|,} ..., ..., xn, yn}}; - * P1x, P1y, P2x, P2y [Integer in ASCII] - * - * PD (Pen Down): Executes pen then moves to the requested position - * if one is specified. This position is dependent on whether absolute - * or relative mode is set. This command performs no motion in 3-D mode, - * but the outputs and feedrates are affected. - * PD {x, y}; - * - * PM Polygon mode - * associated commands: - * PM2 End polygon mode - * FP Fill polygon - * EP Draw polygon outline - * - * PR (Plot Relative): Moves to the relative position specified and sets relative mode - * for future PU and PD commands. - * If no arguments follow the command, only relative mode is set. - * PR {Dx1, Dy1 {{PU|PD|,} ..., ..., Dxn, Dyn}}; - * - * PS (Paper Size): - * PS {n}; - * - * PT (Pen Thickness): in mm - * PT {l}; - * - * PU (Pen Up): Executes pen then moves to the requested position - * if one is specified. This position is dependent on whether absolute - * or relative mode is set. - * This command performs no motion in 3-D mode, but the outputs - * and feedrates are affected. - * PU {x, y}; - * - * RA (Rectangle Absolute - Filled, from current position to diagonal x,y): - * RA x, y; - * - * RO (Rotate Coordinate System): - * RO; - * - * RR (Rectangle Relative - Filled, from current position to diagonal x,y): - * RR x, y; - * - * SA (Select Alternate Set): - * SA; - * - * SC (Scale): - * SC {Xmin, Xmax, Ymin, Ymax}; - * - * SI (Absolute Character Size): - * SI b, h; - * b [-127.9999 .. 127.9999, keine 0] - * h [-127.9999 .. 127.9999, keine 0] - * - * SL (Character Slant): - * SL {a}; - * a [-3.5 .. -0.5, 0.5 .. 3.5] -* - * SP (Select Pen): Selects a new pen or tool for use. - * If no pen number or a value of zero is given, - * the controller performs an EOF (end of file command). - * Once an EOF is performed, no motion is executed, - * until a new IN command is received. - * SP n; - * - * SR (Relative Character Size): - * SR {b, h}; - * b [-127.9999 .. 127.9999, keine 0] - * h [-127.9999 .. 127.9999, keine 0] - * - * SS (Select Standard Set): - * SS; - * - * TL (Tick Length): - * TL {tp {, tm}}; - * - * UC (User Defined Character): - * UC {i,} x1, y1, {i,} x2, y2, ... {i,} xn, yn; - * - * VS (Velocity Select): - * VS {v {, n}}; - * v [1 .. 40] in cm/s - * n [1 .. 8] - * - * XT (X Tick): - * XT; - * - * YT (Y Tick): - * YT; - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// The hpgl command to close a polygon def, fill it and plot outline: -// PM 2; ends the polygon definition and closes it if not closed -// FP; fills the polygon -// EP; draws the polygon outline. It usually gives a better look to the filled polygon -static const char hpgl_end_polygon_cmd[] = "PM 2; FP; EP;\n"; - -// HPGL scale factor (1 PLU = 1/40mm = 25 micrometers) -static const double PLUsPERDECIMIL = 0.102041; - -HPGL_PLOTTER::HPGL_PLOTTER() -{ - SetPenSpeed( 40 ); // Default pen speed = 40 cm/s; Pen speed is *always* in cm - SetPenNumber( 1 ); // Default pen num = 1 - SetPenDiameter( 0.0 ); -} - -void HPGL_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil, - double aScale, bool aMirror ) -{ - plotOffset = aOffset; - plotScale = aScale; - m_IUsPerDecimil = aIusPerDecimil; - iuPerDeviceUnit = PLUsPERDECIMIL / aIusPerDecimil; - /* Compute the paper size in IUs */ - paperSize = pageInfo.GetSizeMils(); - paperSize.x *= 10.0 * aIusPerDecimil; - paperSize.y *= 10.0 * aIusPerDecimil; - SetDefaultLineWidth( 0 ); // HPGL has pen sizes instead - m_plotMirror = aMirror; -} - - -/** - * At the start of the HPGL plot pen speed and number are requested - */ -bool HPGL_PLOTTER::StartPlot() -{ - wxASSERT( outputFile ); - fprintf( outputFile, "IN;VS%d;PU;PA;SP%d;\n", penSpeed, penNumber ); - - // Set HPGL Pen Thickness (in mm) (usefull in polygon fill command) - double penThicknessMM = userToDeviceSize( penDiameter )/40; - fprintf( outputFile, "PT %.1f;\n", penThicknessMM ); - - return true; -} - - -/** - * HPGL end of plot: pen return and release - */ -bool HPGL_PLOTTER::EndPlot() -{ - wxASSERT( outputFile ); - fputs( "PU;PA;SP0;\n", outputFile ); - fclose( outputFile ); - outputFile = NULL; - return true; -} - - -void HPGL_PLOTTER::SetPenDiameter( double diameter ) -{ - penDiameter = diameter; -} - -/** - * HPGL rectangle: fill not supported - */ -void HPGL_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width ) -{ - wxASSERT( outputFile ); - DPOINT p2dev = userToDeviceCoordinates( p2 ); - MoveTo( p1 ); - fprintf( outputFile, "EA %.0f,%.0f;\n", p2dev.x, p2dev.y ); - PenFinish(); -} - - -// HPGL circle -void HPGL_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_T fill, - int width ) -{ - wxASSERT( outputFile ); - double radius = userToDeviceSize( diameter / 2 ); - SetCurrentLineWidth( width ); - - if( fill == FILLED_SHAPE ) - { - // Draw the filled area - MoveTo( centre ); - fprintf( outputFile, "PM 0; CI %g;\n", radius ); - fprintf( outputFile, hpgl_end_polygon_cmd ); // Close, fill polygon and draw outlines - PenFinish(); - } - - if( radius > 0 ) - { - MoveTo( centre ); - fprintf( outputFile, "CI %g;\n", radius ); - PenFinish(); - } -} - - -/** - * HPGL polygon: - */ - -void HPGL_PLOTTER::PlotPoly( const std::vector& aCornerList, - FILL_T aFill, int aWidth, void * aData ) -{ - if( aCornerList.size() <= 1 ) - return; - - SetCurrentLineWidth( aWidth ); - MoveTo( aCornerList[0] ); - - if( aFill == FILLED_SHAPE ) - { - // Draw the filled area - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); - fprintf( outputFile, "PM 0;\n" ); // Start polygon - - for( unsigned ii = 1; ii < aCornerList.size(); ++ii ) - LineTo( aCornerList[ii] ); - - int ii = aCornerList.size() - 1; - - if( aCornerList[ii] != aCornerList[0] ) - LineTo( aCornerList[0] ); - - fprintf( outputFile, hpgl_end_polygon_cmd ); // Close, fill polygon and draw outlines - } - else - { - // Plot only the polygon outline. - for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) - LineTo( aCornerList[ii] ); - - // Always close polygon if filled. - if( aFill ) - { - int ii = aCornerList.size() - 1; - - if( aCornerList[ii] != aCornerList[0] ) - LineTo( aCornerList[0] ); - } - } - - PenFinish(); -} - - -/** - * Pen control logic (remove redundant pen activations) - */ -void HPGL_PLOTTER::penControl( char plume ) -{ - wxASSERT( outputFile ); - - switch( plume ) - { - case 'U': - - if( penState != 'U' ) - { - fputs( "PU;", outputFile ); - penState = 'U'; - } - - break; - - case 'D': - - if( penState != 'D' ) - { - fputs( "PD;", outputFile ); - penState = 'D'; - } - - break; - - case 'Z': - fputs( "PU;", outputFile ); - penState = 'U'; - penLastpos.x = -1; - penLastpos.y = -1; - break; - } -} - - -void HPGL_PLOTTER::PenTo( const wxPoint& pos, char plume ) -{ - wxASSERT( outputFile ); - - if( plume == 'Z' ) - { - penControl( 'Z' ); - return; - } - - penControl( plume ); - DPOINT pos_dev = userToDeviceCoordinates( pos ); - - if( penLastpos != pos ) - fprintf( outputFile, "PA %.0f,%.0f;\n", pos_dev.x, pos_dev.y ); - - penLastpos = pos; -} - - -/** - * HPGL supports dashed lines - */ -void HPGL_PLOTTER::SetDash( int dashed ) -{ - wxASSERT( outputFile ); - - switch( dashed ) - { - case PLOTDASHTYPE_DASH: - fprintf( outputFile, "LT -2 4 1;\n" ); - break; - case PLOTDASHTYPE_DOT: - fprintf( outputFile, "LT -1 2 1;\n" ); - break; - case PLOTDASHTYPE_DASHDOT: - fprintf( outputFile, "LT -4 6 1;\n" ); - break; - default: - fputs( "LT;\n", outputFile ); - } -} - - -void HPGL_PLOTTER::ThickSegment( const wxPoint& start, const wxPoint& end, - int width, EDA_DRAW_MODE_T tracemode, void* aData ) -{ - wxASSERT( outputFile ); - wxPoint center; - wxSize size; - - // Suppress overlap if pen is too big - if( penDiameter >= width ) - { - MoveTo( start ); - FinishTo( end ); - } - else - segmentAsOval( start, end, width, tracemode ); -} - - -/* Plot an arc: - * Center = center coord - * Stangl, endAngle = angle of beginning and end - * Radius = radius of the arc - * Command - * PU PY x, y; PD start_arc_X AA, start_arc_Y, angle, NbSegm; PU; - * Or PU PY x, y; PD start_arc_X AA, start_arc_Y, angle, PU; - */ -void HPGL_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius, - FILL_T fill, int width ) -{ - wxASSERT( outputFile ); - double angle; - - if( radius <= 0 ) - return; - - DPOINT centre_dev = userToDeviceCoordinates( centre ); - - if( m_plotMirror ) - angle = StAngle - EndAngle; - else - angle = EndAngle - StAngle; - - NORMALIZE_ANGLE_180( angle ); - angle /= 10; - - // Calculate arc start point: - wxPoint cmap; - cmap.x = centre.x + KiROUND( cosdecideg( radius, StAngle ) ); - cmap.y = centre.y - KiROUND( sindecideg( radius, StAngle ) ); - DPOINT cmap_dev = userToDeviceCoordinates( cmap ); - - fprintf( outputFile, - "PU;PA %.0f,%.0f;PD;AA %.0f,%.0f,", - cmap_dev.x, cmap_dev.y, - centre_dev.x, centre_dev.y ); - fprintf( outputFile, "%.0f", angle ); - fprintf( outputFile, ";PU;\n" ); - PenFinish(); -} - - -/* Plot oval pad. - */ -void HPGL_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, double orient, - EDA_DRAW_MODE_T trace_mode, void* aData ) -{ - wxASSERT( outputFile ); - int deltaxy, cx, cy; - wxSize size( aSize ); - - /* The pad will be drawn as an oblong shape with size.y > size.x - * (Oval vertical orientation 0) - */ - if( size.x > size.y ) - { - std::swap( size.x, size.y ); - orient = AddAngles( orient, 900 ); - } - - deltaxy = size.y - size.x; // distance between centers of the oval - - if( trace_mode == FILLED ) - { - FlashPadRect( pos, wxSize( size.x, deltaxy + KiROUND( penDiameter ) ), - orient, trace_mode, aData ); - cx = 0; cy = deltaxy / 2; - RotatePoint( &cx, &cy, orient ); - FlashPadCircle( wxPoint( cx + pos.x, cy + pos.y ), size.x, trace_mode, aData ); - cx = 0; cy = -deltaxy / 2; - RotatePoint( &cx, &cy, orient ); - FlashPadCircle( wxPoint( cx + pos.x, cy + pos.y ), size.x, trace_mode, aData ); - } - else // Plot in outline mode. - { - sketchOval( pos, size, orient, KiROUND( penDiameter ) ); - } -} - - -/* Plot round pad or via. - */ -void HPGL_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre, - EDA_DRAW_MODE_T trace_mode, void* aData ) -{ - wxASSERT( outputFile ); - DPOINT pos_dev = userToDeviceCoordinates( pos ); - - int radius = diametre / 2; - - if( trace_mode == FILLED ) - { - // if filled mode, the pen diameter is removed from diameter - // to keep the pad size - radius -= KiROUND( penDiameter ) / 2; - } - - if( radius < 0 ) - radius = 0; - - double rsize = userToDeviceSize( radius ); - - if( trace_mode == FILLED ) // Plot in filled mode. - { - // A filled polygon uses always the current point to start the polygon. - // Gives a correct current starting point for the circle - MoveTo( wxPoint( pos.x+radius, pos.y ) ); - // Plot filled area and its outline - fprintf( outputFile, "PM 0; PA %.0f,%.0f;CI %.0f;%s", - pos_dev.x, pos_dev.y, rsize, hpgl_end_polygon_cmd ); - } - else - { - // Draw outline only: - fprintf( outputFile, "PA %.0f,%.0f;CI %.0f;\n", - pos_dev.x, pos_dev.y, rsize ); - } - - PenFinish(); -} - - -void HPGL_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& padsize, - double orient, EDA_DRAW_MODE_T trace_mode, void* aData ) -{ - // Build rect polygon: - std::vector corners; - - int dx = padsize.x / 2; - int dy = padsize.y / 2; - - if( trace_mode == FILLED ) - { - // in filled mode, the pen diameter is removed from size - // to compensate the extra size due to this pen size - dx -= KiROUND( penDiameter ) / 2; - dx = std::max( dx, 0); - dy -= KiROUND( penDiameter ) / 2; - dy = std::max( dy, 0); - } - - - corners.push_back( wxPoint( - dx, - dy ) ); - corners.push_back( wxPoint( - dx, + dy ) ); - corners.push_back( wxPoint( + dx, + dy ) ); - corners.push_back( wxPoint( + dx, - dy ) ); - - - for( unsigned ii = 0; ii < corners.size(); ii++ ) - { - RotatePoint( &corners[ii], orient ); - corners[ii] += pos; - } - - PlotPoly( corners, trace_mode == FILLED ? FILLED_SHAPE : NO_FILL ); -} - - -void HPGL_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize, - int aCornerRadius, double aOrient, - EDA_DRAW_MODE_T aTraceMode, void* aData ) -{ - SHAPE_POLY_SET outline; - const int segmentToCircleCount = 32; - - wxSize size = aSize; - - if( aTraceMode == FILLED ) - { - // in filled mode, the pen diameter is removed from size - // to keep the pad size - size.x -= KiROUND( penDiameter ) / 2; - size.x = std::max( size.x, 0); - size.y -= KiROUND( penDiameter ) / 2; - size.y = std::max( size.y, 0); - - // keep aCornerRadius to a value < min size x,y < 2: - aCornerRadius = std::min( aCornerRadius, std::min( size.x, size.y ) /2 ); - } - - TransformRoundRectToPolygon( outline, aPadPos, size, aOrient, - aCornerRadius, segmentToCircleCount ); - - // TransformRoundRectToPolygon creates only one convex polygon - std::vector< wxPoint > cornerList; - cornerList.reserve( segmentToCircleCount + 4 ); - SHAPE_LINE_CHAIN& poly = outline.Outline( 0 ); - - for( int ii = 0; ii < poly.PointCount(); ++ii ) - cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) ); - - PlotPoly( cornerList, aTraceMode == FILLED ? FILLED_SHAPE : NO_FILL ); -} - -void HPGL_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize, - SHAPE_POLY_SET* aPolygons, - EDA_DRAW_MODE_T aTraceMode, void* aData ) -{ - std::vector< wxPoint > cornerList; - - for( int cnt = 0; cnt < aPolygons->OutlineCount(); ++cnt ) - { - SHAPE_LINE_CHAIN& poly = aPolygons->Outline( cnt ); - - cornerList.clear(); - cornerList.reserve( poly.PointCount() ); - - for( int ii = 1; ii < poly.PointCount(); ++ii ) - cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) ); - - PlotPoly( cornerList, aTraceMode == FILLED ? FILLED_SHAPE : NO_FILL ); - } -} - - -void HPGL_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCorners, - double aPadOrient, EDA_DRAW_MODE_T aTraceMode, void* aData ) -{ - std::vector< wxPoint > cornerList; - cornerList.reserve( 4 ); - - for( int ii = 0; ii < 4; ii++ ) - { - wxPoint coord( aCorners[ii] ); - RotatePoint( &coord, aPadOrient ); - coord += aPadPos; - cornerList.push_back( coord ); - } - - PlotPoly( cornerList, aTraceMode == FILLED ? FILLED_SHAPE : NO_FILL ); -} diff --git a/common/plotters/common_plotPDF_functions.cpp b/common/plotters/common_plotPDF_functions.cpp deleted file mode 100644 index 990faf1a3d..0000000000 --- a/common/plotters/common_plotPDF_functions.cpp +++ /dev/null @@ -1,857 +0,0 @@ -/** - * @file common_plotPDF_functions.cpp - * @brief Kicad: Common plot PDF Routines - */ - -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 1992-2012 Lorenzo Marcantonio, l.marcantonio@logossrl.com - * Copyright (C) 1992-2017 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * Open or create the plot file aFullFilename - * return true if success, false if the file cannot be created/opened - * - * Opens the PDF file in binary mode - */ -bool PDF_PLOTTER::OpenFile( const wxString& aFullFilename ) -{ - filename = aFullFilename; - - wxASSERT( !outputFile ); - - // Open the PDF file in binary mode - outputFile = wxFopen( filename, wxT( "wb" ) ); - - if( outputFile == NULL ) - return false ; - - return true; -} - -void PDF_PLOTTER::SetPageSettings( const PAGE_INFO& aPageSettings ) -{ - pageInfo = aPageSettings; -} - -void PDF_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil, - double aScale, bool aMirror ) -{ - m_plotMirror = aMirror; - plotOffset = aOffset; - plotScale = aScale; - m_IUsPerDecimil = aIusPerDecimil; - - // The CTM is set to 1 user unit per decimil - iuPerDeviceUnit = 1.0 / aIusPerDecimil; - - SetDefaultLineWidth( 100 / iuPerDeviceUnit ); // arbitrary default - - /* The paper size in this engined is handled page by page - Look in the StartPage function */ -} - - -/** - * Pen width setting for PDF. Since the specs *explicitly* says that a 0 - * width is a bad thing to use (since it results in 1 pixel traces), we - * convert such requests to the minimal width (like 1) - * Note pen width = 0 is used in plot polygons to plot filled polygons with - * no outline thickness - * use in this case pen width = 1 does not actally change the polygon - */ -void PDF_PLOTTER::SetCurrentLineWidth( int width, void* aData ) -{ - wxASSERT( workFile ); - int pen_width; - - if( width > 0 ) - pen_width = width; - else if( width == 0 ) - pen_width = 1; - else - pen_width = defaultPenWidth; - - if( pen_width != currentPenWidth ) - fprintf( workFile, "%g w\n", - userToDeviceSize( pen_width ) ); - - currentPenWidth = pen_width; -} - - -/** - * PDF supports colors fully. It actually has distinct fill and pen colors, - * but we set both at the same time. - * - * XXX Keeping them divided could result in a minor optimization in - * eeschema filled shapes, but would propagate to all the other plot - * engines. Also arcs are filled as pies but only the arc is stroked so - * it would be difficult to handle anyway. - */ -void PDF_PLOTTER::emitSetRGBColor( double r, double g, double b ) -{ - wxASSERT( workFile ); - fprintf( workFile, "%g %g %g rg %g %g %g RG\n", - r, g, b, r, g, b ); -} - -/** - * PDF supports dashed lines - */ -void PDF_PLOTTER::SetDash( int dashed ) -{ - wxASSERT( workFile ); - switch( dashed ) - { - case PLOTDASHTYPE_DASH: - fprintf( workFile, "[%d %d] 0 d\n", - (int) GetDashMarkLenIU(), (int) GetDashGapLenIU() ); - break; - case PLOTDASHTYPE_DOT: - fprintf( workFile, "[%d %d] 0 d\n", - (int) GetDotMarkLenIU(), (int) GetDashGapLenIU() ); - break; - case PLOTDASHTYPE_DASHDOT: - fprintf( workFile, "[%d %d %d %d] 0 d\n", - (int) GetDashMarkLenIU(), (int) GetDashGapLenIU(), - (int) GetDotMarkLenIU(), (int) GetDashGapLenIU() ); - break; - default: - fputs( "[] 0 d\n", workFile ); - } -} - - -/** - * Rectangles in PDF. Supported by the native operator - */ -void PDF_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width ) -{ - wxASSERT( workFile ); - DPOINT p1_dev = userToDeviceCoordinates( p1 ); - DPOINT p2_dev = userToDeviceCoordinates( p2 ); - - SetCurrentLineWidth( width ); - fprintf( workFile, "%g %g %g %g re %c\n", p1_dev.x, p1_dev.y, - p2_dev.x - p1_dev.x, p2_dev.y - p1_dev.y, - fill == NO_FILL ? 'S' : 'B' ); -} - - -/** - * Circle drawing for PDF. They're approximated by curves, but fill is supported - */ -void PDF_PLOTTER::Circle( const wxPoint& pos, int diametre, FILL_T aFill, int width ) -{ - wxASSERT( workFile ); - DPOINT pos_dev = userToDeviceCoordinates( pos ); - double radius = userToDeviceSize( diametre / 2.0 ); - - /* OK. Here's a trick. PDF doesn't support circles or circular angles, that's - a fact. You'll have to do with cubic beziers. These *can't* represent - circular arcs (NURBS can, beziers don't). But there is a widely known - approximation which is really good - */ - - SetCurrentLineWidth( width ); - double magic = radius * 0.551784; // You don't want to know where this come from - - // This is the convex hull for the bezier approximated circle - fprintf( workFile, "%g %g m " - "%g %g %g %g %g %g c " - "%g %g %g %g %g %g c " - "%g %g %g %g %g %g c " - "%g %g %g %g %g %g c %c\n", - pos_dev.x - radius, pos_dev.y, - - pos_dev.x - radius, pos_dev.y + magic, - pos_dev.x - magic, pos_dev.y + radius, - pos_dev.x, pos_dev.y + radius, - - pos_dev.x + magic, pos_dev.y + radius, - pos_dev.x + radius, pos_dev.y + magic, - pos_dev.x + radius, pos_dev.y, - - pos_dev.x + radius, pos_dev.y - magic, - pos_dev.x + magic, pos_dev.y - radius, - pos_dev.x, pos_dev.y - radius, - - pos_dev.x - magic, pos_dev.y - radius, - pos_dev.x - radius, pos_dev.y - magic, - pos_dev.x - radius, pos_dev.y, - - aFill == NO_FILL ? 's' : 'b' ); -} - - -/** - * The PDF engine can't directly plot arcs, it uses the base emulation. - * So no filled arcs (not a great loss... ) - */ -void PDF_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius, - FILL_T fill, int width ) -{ - wxASSERT( workFile ); - if( radius <= 0 ) - return; - - /* Arcs are not so easily approximated by beziers (in the general case), - so we approximate them in the old way */ - wxPoint start, end; - const int delta = 50; // increment (in 0.1 degrees) to draw circles - - if( StAngle > EndAngle ) - std::swap( StAngle, EndAngle ); - - SetCurrentLineWidth( width ); - - // Usual trig arc plotting routine... - start.x = centre.x + KiROUND( cosdecideg( radius, -StAngle ) ); - start.y = centre.y + KiROUND( sindecideg( radius, -StAngle ) ); - DPOINT pos_dev = userToDeviceCoordinates( start ); - fprintf( workFile, "%g %g m ", pos_dev.x, pos_dev.y ); - for( int ii = StAngle + delta; ii < EndAngle; ii += delta ) - { - end.x = centre.x + KiROUND( cosdecideg( radius, -ii ) ); - end.y = centre.y + KiROUND( sindecideg( radius, -ii ) ); - pos_dev = userToDeviceCoordinates( end ); - fprintf( workFile, "%g %g l ", pos_dev.x, pos_dev.y ); - } - - end.x = centre.x + KiROUND( cosdecideg( radius, -EndAngle ) ); - end.y = centre.y + KiROUND( sindecideg( radius, -EndAngle ) ); - pos_dev = userToDeviceCoordinates( end ); - fprintf( workFile, "%g %g l ", pos_dev.x, pos_dev.y ); - - // The arc is drawn... if not filled we stroke it, otherwise we finish - // closing the pie at the center - if( fill == NO_FILL ) - { - fputs( "S\n", workFile ); - } - else - { - pos_dev = userToDeviceCoordinates( centre ); - fprintf( workFile, "%g %g l b\n", pos_dev.x, pos_dev.y ); - } -} - - -/** - * Polygon plotting for PDF. Everything is supported - */ -void PDF_PLOTTER::PlotPoly( const std::vector< wxPoint >& aCornerList, - FILL_T aFill, int aWidth, void * aData ) -{ - wxASSERT( workFile ); - if( aCornerList.size() <= 1 ) - return; - - SetCurrentLineWidth( aWidth ); - - DPOINT pos = userToDeviceCoordinates( aCornerList[0] ); - fprintf( workFile, "%g %g m\n", pos.x, pos.y ); - - for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) - { - pos = userToDeviceCoordinates( aCornerList[ii] ); - fprintf( workFile, "%g %g l\n", pos.x, pos.y ); - } - - // Close path and stroke(/fill) - fprintf( workFile, "%c\n", aFill == NO_FILL ? 'S' : 'b' ); -} - - -void PDF_PLOTTER::PenTo( const wxPoint& pos, char plume ) -{ - wxASSERT( workFile ); - if( plume == 'Z' ) - { - if( penState != 'Z' ) - { - fputs( "S\n", workFile ); - penState = 'Z'; - penLastpos.x = -1; - penLastpos.y = -1; - } - return; - } - - if( penState != plume || pos != penLastpos ) - { - DPOINT pos_dev = userToDeviceCoordinates( pos ); - fprintf( workFile, "%g %g %c\n", - pos_dev.x, pos_dev.y, - ( plume=='D' ) ? 'l' : 'm' ); - } - penState = plume; - penLastpos = pos; -} - -/** - * PDF images are handles as inline, not XObject streams... - */ -void PDF_PLOTTER::PlotImage( const wxImage & aImage, const wxPoint& aPos, - double aScaleFactor ) -{ - wxASSERT( workFile ); - wxSize pix_size( aImage.GetWidth(), aImage.GetHeight() ); - - // Requested size (in IUs) - DPOINT drawsize( aScaleFactor * pix_size.x, - aScaleFactor * pix_size.y ); - - // calculate the bitmap start position - wxPoint start( aPos.x - drawsize.x / 2, - aPos.y + drawsize.y / 2); - - DPOINT dev_start = userToDeviceCoordinates( start ); - - /* PDF has an uhm... simplified coordinate system handling. There is - *one* operator to do everything (the PS concat equivalent). At least - they kept the matrix stack to save restore environments. Also images - are always emitted at the origin with a size of 1x1 user units. - What we need to do is: - 1) save the CTM end estabilish the new one - 2) plot the image - 3) restore the CTM - 4) profit - */ - fprintf( workFile, "q %g 0 0 %g %g %g cm\n", // Step 1 - userToDeviceSize( drawsize.x ), - userToDeviceSize( drawsize.y ), - dev_start.x, dev_start.y ); - - /* An inline image is a cross between a dictionary and a stream. - A real ugly construct (compared with the elegance of the PDF - format). Also it accepts some 'abbreviations', which is stupid - since the content stream is usually compressed anyway... */ - fprintf( workFile, - "BI\n" - " /BPC 8\n" - " /CS %s\n" - " /W %d\n" - " /H %d\n" - "ID\n", colorMode ? "/RGB" : "/G", pix_size.x, pix_size.y ); - - /* Here comes the stream (in binary!). I *could* have hex or ascii84 - encoded it, but who cares? I'll go through zlib anyway */ - for( int y = 0; y < pix_size.y; y++ ) - { - for( int x = 0; x < pix_size.x; x++ ) - { - unsigned char r = aImage.GetRed( x, y ) & 0xFF; - unsigned char g = aImage.GetGreen( x, y ) & 0xFF; - unsigned char b = aImage.GetBlue( x, y ) & 0xFF; - // As usual these days, stdio buffering has to suffeeeeerrrr - if( colorMode ) - { - putc( r, workFile ); - putc( g, workFile ); - putc( b, workFile ); - } - else - { - // Grayscale conversion - putc( (r + g + b) / 3, workFile ); - } - } - } - - fputs( "EI Q\n", workFile ); // Finish step 2 and do step 3 -} - - -/** - * Allocate a new handle in the table of the PDF object. The - * handle must be completed using startPdfObject. It's an in-RAM operation - * only, no output is done. - */ -int PDF_PLOTTER::allocPdfObject() -{ - xrefTable.push_back( 0 ); - return xrefTable.size() - 1; -} - - -/** - * Open a new PDF object and returns the handle if the parameter is -1. - * Otherwise fill in the xref entry for the passed object - */ -int PDF_PLOTTER::startPdfObject(int handle) -{ - wxASSERT( outputFile ); - wxASSERT( !workFile ); - - if( handle < 0) - handle = allocPdfObject(); - - xrefTable[handle] = ftell( outputFile ); - fprintf( outputFile, "%d 0 obj\n", handle ); - return handle; -} - - -/** - * Close the current PDF object - */ -void PDF_PLOTTER::closePdfObject() -{ - wxASSERT( outputFile ); - wxASSERT( !workFile ); - fputs( "endobj\n", outputFile ); -} - - -/** - * Starts a PDF stream (for the page). Returns the object handle opened - * Pass -1 (default) for a fresh object. Especially from PDF 1.5 streams - * can contain a lot of things, but for the moment we only handle page - * content. - */ -int PDF_PLOTTER::startPdfStream(int handle) -{ - wxASSERT( outputFile ); - wxASSERT( !workFile ); - handle = startPdfObject( handle ); - - // This is guaranteed to be handle+1 but needs to be allocated since - // you could allocate more object during stream preparation - streamLengthHandle = allocPdfObject(); - fprintf( outputFile, - "<< /Length %d 0 R /Filter /FlateDecode >>\n" // Length is deferred - "stream\n", handle + 1 ); - - // Open a temporary file to accumulate the stream - workFilename = filename + wxT(".tmp"); - workFile = wxFopen( workFilename, wxT( "w+b" )); - wxASSERT( workFile ); - return handle; -} - - -/** - * Finish the current PDF stream (writes the deferred length, too) - */ -void PDF_PLOTTER::closePdfStream() -{ - wxASSERT( workFile ); - - long stream_len = ftell( workFile ); - - if( stream_len < 0 ) - { - wxASSERT( false ); - return; - } - - // Rewind the file, read in the page stream and DEFLATE it - fseek( workFile, 0, SEEK_SET ); - unsigned char *inbuf = new unsigned char[stream_len]; - - int rc = fread( inbuf, 1, stream_len, workFile ); - wxASSERT( rc == stream_len ); - (void) rc; - - // We are done with the temporary file, junk it - fclose( workFile ); - workFile = 0; - ::wxRemoveFile( workFilename ); - - // NULL means memos owns the memory, but provide a hint on optimum size needed. - wxMemoryOutputStream memos( NULL, std::max( 2000l, stream_len ) ) ; - - { - /* Somewhat standard parameters to compress in DEFLATE. The PDF spec is - * misleading, it says it wants a DEFLATE stream but it really want a ZLIB - * stream! (a DEFLATE stream would be generated with -15 instead of 15) - * rc = deflateInit2( &zstrm, Z_BEST_COMPRESSION, Z_DEFLATED, 15, - * 8, Z_DEFAULT_STRATEGY ); - */ - - wxZlibOutputStream zos( memos, wxZ_BEST_COMPRESSION, wxZLIB_ZLIB ); - - zos.Write( inbuf, stream_len ); - - delete[] inbuf; - - } // flush the zip stream using zos destructor - - wxStreamBuffer* sb = memos.GetOutputStreamBuffer(); - - unsigned out_count = sb->Tell(); - - fwrite( sb->GetBufferStart(), 1, out_count, outputFile ); - - fputs( "endstream\n", outputFile ); - closePdfObject(); - - // Writing the deferred length as an indirect object - startPdfObject( streamLengthHandle ); - fprintf( outputFile, "%u\n", out_count ); - closePdfObject(); -} - -/** - * Starts a new page in the PDF document - */ -void PDF_PLOTTER::StartPage() -{ - wxASSERT( outputFile ); - wxASSERT( !workFile ); - - // Compute the paper size in IUs - paperSize = pageInfo.GetSizeMils(); - paperSize.x *= 10.0 / iuPerDeviceUnit; - paperSize.y *= 10.0 / iuPerDeviceUnit; - - // Open the content stream; the page object will go later - pageStreamHandle = startPdfStream(); - - /* Now, until ClosePage *everything* must be wrote in workFile, to be - compressed later in closePdfStream */ - - // Default graphic settings (coordinate system, default color and line style) - fprintf( workFile, - "%g 0 0 %g 0 0 cm 1 J 1 j 0 0 0 rg 0 0 0 RG %g w\n", - 0.0072 * plotScaleAdjX, 0.0072 * plotScaleAdjY, - userToDeviceSize( defaultPenWidth ) ); -} - -/** - * Close the current page in the PDF document (and emit its compressed stream) - */ -void PDF_PLOTTER::ClosePage() -{ - wxASSERT( workFile ); - - // Close the page stream (and compress it) - closePdfStream(); - - // Emit the page object and put it in the page list for later - pageHandles.push_back( startPdfObject() ); - - /* Page size is in 1/72 of inch (default user space units) - Works like the bbox in postscript but there is no need for - swapping the sizes, since PDF doesn't require a portrait page. - We use the MediaBox but PDF has lots of other less used boxes - to use */ - - const double BIGPTsPERMIL = 0.072; - wxSize psPaperSize = pageInfo.GetSizeMils(); - - fprintf( outputFile, - "<<\n" - "/Type /Page\n" - "/Parent %d 0 R\n" - "/Resources <<\n" - " /ProcSet [/PDF /Text /ImageC /ImageB]\n" - " /Font %d 0 R >>\n" - "/MediaBox [0 0 %d %d]\n" - "/Contents %d 0 R\n" - ">>\n", - pageTreeHandle, - fontResDictHandle, - int( ceil( psPaperSize.x * BIGPTsPERMIL ) ), - int( ceil( psPaperSize.y * BIGPTsPERMIL ) ), - pageStreamHandle ); - closePdfObject(); - - // Mark the page stream as idle - pageStreamHandle = 0; -} - -/** - * The PDF engine supports multiple pages; the first one is opened - * 'for free' the following are to be closed and reopened. Between - * each page parameters can be set - */ -bool PDF_PLOTTER::StartPlot() -{ - wxASSERT( outputFile ); - - // First things first: the customary null object - xrefTable.clear(); - xrefTable.push_back( 0 ); - - /* The header (that's easy!). The second line is binary junk required - to make the file binary from the beginning (the important thing is - that they must have the bit 7 set) */ - fputs( "%PDF-1.5\n%\200\201\202\203\n", outputFile ); - - /* Allocate an entry for the page tree root, it will go in every page - parent entry */ - pageTreeHandle = allocPdfObject(); - - /* In the same way, the font resource dictionary is used by every page - (it *could* be inherited via the Pages tree */ - fontResDictHandle = allocPdfObject(); - - /* Now, the PDF is read from the end, (more or less)... so we start - with the page stream for page 1. Other more important stuff is written - at the end */ - StartPage(); - return true; -} - - -bool PDF_PLOTTER::EndPlot() -{ - wxASSERT( outputFile ); - - // Close the current page (often the only one) - ClosePage(); - - /* We need to declare the resources we're using (fonts in particular) - The useful standard one is the Helvetica family. Adding external fonts - is *very* involved! */ - struct { - const char *psname; - const char *rsname; - int font_handle; - } fontdefs[4] = { - { "/Helvetica", "/KicadFont", 0 }, - { "/Helvetica-Oblique", "/KicadFontI", 0 }, - { "/Helvetica-Bold", "/KicadFontB", 0 }, - { "/Helvetica-BoldOblique", "/KicadFontBI", 0 } - }; - - /* Declare the font resources. Since they're builtin fonts, no descriptors (yay!) - We'll need metrics anyway to do any aligment (these are in the shared with - the postscript engine) */ - for( int i = 0; i < 4; i++ ) - { - fontdefs[i].font_handle = startPdfObject(); - fprintf( outputFile, - "<< /BaseFont %s\n" - " /Type /Font\n" - " /Subtype /Type1\n" - - /* Adobe is so Mac-based that the nearest thing to Latin1 is - the Windows ANSI encoding! */ - " /Encoding /WinAnsiEncoding\n" - ">>\n", - fontdefs[i].psname ); - closePdfObject(); - } - - // Named font dictionary (was allocated, now we emit it) - startPdfObject( fontResDictHandle ); - fputs( "<<\n", outputFile ); - for( int i = 0; i < 4; i++ ) - { - fprintf( outputFile, " %s %d 0 R\n", - fontdefs[i].rsname, fontdefs[i].font_handle ); - } - fputs( ">>\n", outputFile ); - closePdfObject(); - - /* The page tree: it's a B-tree but luckily we only have few pages! - So we use just an array... The handle was allocated at the beginning, - now we instantiate the corresponding object */ - startPdfObject( pageTreeHandle ); - fputs( "<<\n" - "/Type /Pages\n" - "/Kids [\n", outputFile ); - - for( unsigned i = 0; i < pageHandles.size(); i++ ) - fprintf( outputFile, "%d 0 R\n", pageHandles[i] ); - - fprintf( outputFile, - "]\n" - "/Count %ld\n" - ">>\n", (long) pageHandles.size() ); - closePdfObject(); - - - // The info dictionary - int infoDictHandle = startPdfObject(); - char date_buf[250]; - time_t ltime = time( NULL ); - strftime( date_buf, 250, "D:%Y%m%d%H%M%S", - localtime( <ime ) ); - - if( title.IsEmpty() ) - { - // Windows uses '\' and other platforms ue '/' as sepatator - title = filename.AfterLast('\\'); - title = title.AfterLast('/'); - } - - fprintf( outputFile, - "<<\n" - "/Producer (KiCAD PDF)\n" - "/CreationDate (%s)\n" - "/Creator (%s)\n" - "/Title (%s)\n" - "/Trapped false\n", - date_buf, - TO_UTF8( creator ), - TO_UTF8( title ) ); - - fputs( ">>\n", outputFile ); - closePdfObject(); - - // The catalog, at last - int catalogHandle = startPdfObject(); - fprintf( outputFile, - "<<\n" - "/Type /Catalog\n" - "/Pages %d 0 R\n" - "/Version /1.5\n" - "/PageMode /UseNone\n" - "/PageLayout /SinglePage\n" - ">>\n", pageTreeHandle ); - closePdfObject(); - - /* Emit the xref table (format is crucial to the byte, each entry must - be 20 bytes long, and object zero must be done in that way). Also - the offset must be kept along for the trailer */ - long xref_start = ftell( outputFile ); - fprintf( outputFile, - "xref\n" - "0 %ld\n" - "0000000000 65535 f \n", (long) xrefTable.size() ); - for( unsigned i = 1; i < xrefTable.size(); i++ ) - { - fprintf( outputFile, "%010ld 00000 n \n", xrefTable[i] ); - } - - // Done the xref, go for the trailer - fprintf( outputFile, - "trailer\n" - "<< /Size %lu /Root %d 0 R /Info %d 0 R >>\n" - "startxref\n" - "%ld\n" // The offset we saved before - "%%%%EOF\n", - (unsigned long) xrefTable.size(), catalogHandle, infoDictHandle, xref_start ); - - fclose( outputFile ); - outputFile = NULL; - - return true; -} - -void PDF_PLOTTER::Text( const wxPoint& aPos, - const COLOR4D aColor, - const wxString& aText, - double aOrient, - const wxSize& aSize, - enum EDA_TEXT_HJUSTIFY_T aH_justify, - enum EDA_TEXT_VJUSTIFY_T aV_justify, - int aWidth, - bool aItalic, - bool aBold, - bool aMultilineAllowed, - void* aData ) -{ - // PDF files do not like 0 sized texts which create broken files. - if( aSize.x == 0 || aSize.y == 0 ) - return; - - // Fix me: see how to use PDF text mode for multiline texts - if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) ) - aMultilineAllowed = false; // the text has only one line. - - // Emit native PDF text (if requested) - // Currently: is not supported, because only our stroke font is alloxed: disable it - // However, shadowed texts (searchable texts) works reasonably well because - // pixel accurate precision is not requested, so we add searchable texts - // behind our stroked font texts - bool use_native_font = false; - // render_mode 0 shows the text, render_mode 3 is invisible - int render_mode = use_native_font ? 0 : 3; - - const char *fontname = aItalic ? (aBold ? "/KicadFontBI" : "/KicadFontI") - : (aBold ? "/KicadFontB" : "/KicadFont"); - - // Compute the copious tranformation parameters of the Curent Transform Matrix - double ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f; - double wideningFactor, heightFactor; - - computeTextParameters( aPos, aText, aOrient, aSize, m_plotMirror, aH_justify, - aV_justify, aWidth, aItalic, aBold, - &wideningFactor, &ctm_a, &ctm_b, &ctm_c, - &ctm_d, &ctm_e, &ctm_f, &heightFactor ); - - SetColor( aColor ); - SetCurrentLineWidth( aWidth, aData ); - - /* We use the full CTM instead of the text matrix because the same - coordinate system will be used for the overlining. Also the %f - for the trig part of the matrix to avoid %g going in exponential - format (which is not supported) - render_mode 0 shows the text, render_mode 3 is invisible */ - fprintf( workFile, "q %f %f %f %f %g %g cm BT %s %g Tf %d Tr %g Tz ", - ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f, - fontname, heightFactor, render_mode, - wideningFactor * 100 ); - - // The text must be escaped correctly - fputsPostscriptString( workFile, aText ); - fputs( " Tj ET\n", workFile ); - - // We are in text coordinates, plot the overbars, if we're not doing phantom text - if( use_native_font ) - { - std::vector pos_pairs; - postscriptOverlinePositions( aText, aSize.x, aItalic, aBold, &pos_pairs ); - int overbar_y = KiROUND( aSize.y * 1.1 ); - for( unsigned i = 0; i < pos_pairs.size(); i += 2) - { - /* This is a nontrivial situation: we are *not* in the user - coordinate system, so the userToDeviceCoordinates function - can't be used! Strange as it may seem, the userToDeviceSize - is the right function to use here... */ - DPOINT dev_from = userToDeviceSize( wxSize( pos_pairs[i], overbar_y ) ); - DPOINT dev_to = userToDeviceSize( wxSize( pos_pairs[i + 1], overbar_y ) ); - fprintf( workFile, "%g %g m %g %g l ", - dev_from.x, dev_from.y, dev_to.x, dev_to.y ); - } - } - - // Stroke and restore the CTM - fputs( "S Q\n", workFile ); - - // Plot the stroked text (if requested) - if( !use_native_font ) - { - PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify, - aWidth, aItalic, aBold, aMultilineAllowed ); - } -} - diff --git a/common/plotters/common_plotPS_functions.cpp b/common/plotters/common_plotPS_functions.cpp deleted file mode 100644 index 8288b013be..0000000000 --- a/common/plotters/common_plotPS_functions.cpp +++ /dev/null @@ -1,1177 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 2017 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 - */ - -/** - * @file common_plotPS_functions.cpp - * @brief Kicad: Common plot Postscript Routines - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Forward declaration of the font width metrics - (yes extern! this is the way to forward declare variables */ -extern const double hv_widths[256]; -extern const double hvb_widths[256]; -extern const double hvo_widths[256]; -extern const double hvbo_widths[256]; - -const double PSLIKE_PLOTTER::postscriptTextAscent = 0.718; - - -// Common routines for Postscript-like plotting engines - -void PSLIKE_PLOTTER::SetDefaultLineWidth( int width ) -{ - defaultPenWidth = width; - currentPenWidth = -1; -} - - -void PSLIKE_PLOTTER::SetColor( COLOR4D color ) -{ - if( colorMode ) - { - if( negativeMode ) - emitSetRGBColor( 1 - color.r, 1 - color.g, 1 - color.b ); - else - emitSetRGBColor( color.r, color.g, color.b ); - } - else - { - /* B/W Mode - Use BLACK or WHITE for all items - * note the 2 colors are used in B&W mode, mainly by Pcbnew to draw - * holes in white on pads in black - */ - double k = 1; // White - if( color != COLOR4D::WHITE ) - k = 0; - if( negativeMode ) - emitSetRGBColor( 1 - k, 1 - k, 1 - k ); - else - emitSetRGBColor( k, k, k ); - } -} - - -void PSLIKE_PLOTTER::FlashPadOval( const wxPoint& aPadPos, const wxSize& aSize, - double aPadOrient, EDA_DRAW_MODE_T aTraceMode, void* aData ) -{ - wxASSERT( outputFile ); - int x0, y0, x1, y1, delta; - wxSize size( aSize ); - - // The pad is reduced to an oval by dy > dx - if( size.x > size.y ) - { - std::swap( size.x, size.y ); - aPadOrient = AddAngles( aPadOrient, 900 ); - } - - delta = size.y - size.x; - x0 = 0; - y0 = -delta / 2; - x1 = 0; - y1 = delta / 2; - RotatePoint( &x0, &y0, aPadOrient ); - RotatePoint( &x1, &y1, aPadOrient ); - - if( aTraceMode == FILLED ) - ThickSegment( wxPoint( aPadPos.x + x0, aPadPos.y + y0 ), - wxPoint( aPadPos.x + x1, aPadPos.y + y1 ), size.x, aTraceMode, NULL ); - else - sketchOval( aPadPos, size, aPadOrient, -1 ); -} - - -void PSLIKE_PLOTTER::FlashPadCircle( const wxPoint& aPadPos, int aDiameter, - EDA_DRAW_MODE_T aTraceMode, void* aData ) -{ - if( aTraceMode == FILLED ) - Circle( aPadPos, aDiameter, FILLED_SHAPE, 0 ); - else // Plot a ring: - { - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); - int linewidth = GetCurrentLineWidth(); - - // avoid aDiameter <= 1 ) - if( linewidth > aDiameter-2 ) - linewidth = aDiameter-2; - - Circle( aPadPos, aDiameter - linewidth, NO_FILL, linewidth ); - } - - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); -} - - -void PSLIKE_PLOTTER::FlashPadRect( const wxPoint& aPadPos, const wxSize& aSize, - double aPadOrient, EDA_DRAW_MODE_T aTraceMode, void* aData ) -{ - static std::vector< wxPoint > cornerList; - wxSize size( aSize ); - cornerList.clear(); - - if( aTraceMode == FILLED ) - SetCurrentLineWidth( 0 ); - else - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); - - size.x -= GetCurrentLineWidth(); - size.y -= GetCurrentLineWidth(); - - if( size.x < 1 ) - size.x = 1; - - if( size.y < 1 ) - size.y = 1; - - int dx = size.x / 2; - int dy = size.y / 2; - - wxPoint corner; - corner.x = aPadPos.x - dx; - corner.y = aPadPos.y + dy; - cornerList.push_back( corner ); - corner.x = aPadPos.x - dx; - corner.y = aPadPos.y - dy; - cornerList.push_back( corner ); - corner.x = aPadPos.x + dx; - corner.y = aPadPos.y - dy; - cornerList.push_back( corner ); - corner.x = aPadPos.x + dx; - corner.y = aPadPos.y + dy, - cornerList.push_back( corner ); - - for( unsigned ii = 0; ii < cornerList.size(); ii++ ) - { - RotatePoint( &cornerList[ii], aPadPos, aPadOrient ); - } - - cornerList.push_back( cornerList[0] ); - - PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILLED_SHAPE : NO_FILL, - GetCurrentLineWidth() ); -} - -void PSLIKE_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize, - int aCornerRadius, double aOrient, - EDA_DRAW_MODE_T aTraceMode, void* aData ) -{ - wxSize size( aSize ); - - if( aTraceMode == FILLED ) - SetCurrentLineWidth( 0 ); - else - { - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); - size.x -= GetCurrentLineWidth(); - size.y -= GetCurrentLineWidth(); - aCornerRadius -= GetCurrentLineWidth()/2; - } - - - SHAPE_POLY_SET outline; - const int segmentToCircleCount = 64; - TransformRoundRectToPolygon( outline, aPadPos, size, aOrient, - aCornerRadius, segmentToCircleCount ); - - std::vector< wxPoint > cornerList; - cornerList.reserve( segmentToCircleCount + 5 ); - // TransformRoundRectToPolygon creates only one convex polygon - SHAPE_LINE_CHAIN& poly = outline.Outline( 0 ); - - for( int ii = 0; ii < poly.PointCount(); ++ii ) - cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) ); - - // Close polygon - cornerList.push_back( cornerList[0] ); - - PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILLED_SHAPE : NO_FILL, - GetCurrentLineWidth() ); -} - -void PSLIKE_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize, - SHAPE_POLY_SET* aPolygons, - EDA_DRAW_MODE_T aTraceMode, void* aData ) -{ - wxSize size( aSize ); - - if( aTraceMode == FILLED ) - SetCurrentLineWidth( 0 ); - else - { - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); - size.x -= GetCurrentLineWidth(); - size.y -= GetCurrentLineWidth(); - } - - - std::vector< wxPoint > cornerList; - - for( int cnt = 0; cnt < aPolygons->OutlineCount(); ++cnt ) - { - SHAPE_LINE_CHAIN& poly = aPolygons->Outline( cnt ); - cornerList.clear(); - - for( int ii = 0; ii < poly.PointCount(); ++ii ) - cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) ); - - // Close polygon - cornerList.push_back( cornerList[0] ); - - PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILLED_SHAPE : NO_FILL, - GetCurrentLineWidth() ); - } -} - -void PSLIKE_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners, - double aPadOrient, EDA_DRAW_MODE_T aTraceMode, void* aData ) -{ - static std::vector< wxPoint > cornerList; - cornerList.clear(); - - for( int ii = 0; ii < 4; ii++ ) - cornerList.push_back( aCorners[ii] ); - - if( aTraceMode == FILLED ) - { - SetCurrentLineWidth( 0 ); - } - else - { - SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH ); - int w = GetCurrentLineWidth(); - // offset polygon by w - // coord[0] is assumed the lower left - // coord[1] is assumed the upper left - // coord[2] is assumed the upper right - // coord[3] is assumed the lower right - - /* Trace the outline. */ - cornerList[0].x += w; - cornerList[0].y -= w; - cornerList[1].x += w; - cornerList[1].y += w; - cornerList[2].x -= w; - cornerList[2].y += w; - cornerList[3].x -= w; - cornerList[3].y -= w; - } - - for( int ii = 0; ii < 4; ii++ ) - { - RotatePoint( &cornerList[ii], aPadOrient ); - cornerList[ii] += aPadPos; - } - - cornerList.push_back( cornerList[0] ); - PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILLED_SHAPE : NO_FILL, - GetCurrentLineWidth() ); -} - - -/** - * Write on a stream a string escaped for postscript/PDF - */ -void PSLIKE_PLOTTER::fputsPostscriptString(FILE *fout, const wxString& txt) -{ - putc( '(', fout ); - for( unsigned i = 0; i < txt.length(); i++ ) - { - // Lazyness made me use stdio buffering yet another time... - wchar_t ch = txt[i]; - - if( ch < 256 ) - { - switch (ch) - { - // The ~ shouldn't reach the outside - case '~': - break; - // These characters must be escaped - case '(': - case ')': - case '\\': - putc( '\\', fout ); - - // FALLTHRU - default: - putc( ch, fout ); - break; - } - } - } - - putc( ')', fout ); -} - - -/** - * Sister function for the GraphicTextWidth in drawtxt.cpp - * Does the same processing (i.e. calculates a text string width) but - * using postscript metrics for the Helvetica font (optionally used for - * PS and PDF plotting - */ -int PSLIKE_PLOTTER::returnPostscriptTextWidth( const wxString& aText, int aXSize, - bool aItalic, bool aBold ) -{ - const double *width_table = aBold ? ( aItalic ? hvbo_widths : hvb_widths ) - : ( aItalic ? hvo_widths : hv_widths ); - double tally = 0; - - for( unsigned i = 0; i < aText.length(); i++ ) - { - wchar_t AsciiCode = aText[i]; - // Skip the negation marks and untabled points - if( AsciiCode != '~' && AsciiCode < 256 ) - { - tally += width_table[AsciiCode]; - } - } - - // Widths are proportional to height, but height is enlarged by a - // scaling factor - return KiROUND( aXSize * tally / postscriptTextAscent ); -} - - -/** - * Computes the x coordinates for the overlining in a string of text. - * Fills the passed vector with couples of (start, stop) values to be - * used in the text coordinate system (use computeTextParameters to - * obtain the parameters to estabilish such a system) - */ -void PSLIKE_PLOTTER::postscriptOverlinePositions( const wxString& aText, int aXSize, - bool aItalic, bool aBold, - std::vector *pos_pairs ) -{ - /* XXX This function is *too* similar to returnPostscriptTextWidth. - Consider merging them... */ - const double *width_table = aBold ? ( aItalic ? hvbo_widths : hvb_widths ) - : ( aItalic ? hvo_widths : hv_widths ); - double tally = 0; - - for( unsigned i = 0; i < aText.length(); i++ ) - { - wchar_t AsciiCode = aText[i]; - // Skip the negation marks and untabled points - if( AsciiCode != '~' && AsciiCode < 256 ) - { - tally += width_table[AsciiCode]; - } - else - { - if( AsciiCode == '~' ) - pos_pairs->push_back( KiROUND( aXSize * tally / postscriptTextAscent ) ); - } - } - - // Special rule: we have to complete the last bar if the ~ aren't matched - if( pos_pairs->size() % 2 == 1 ) - pos_pairs->push_back( KiROUND( aXSize * tally / postscriptTextAscent ) ); -} - -void PS_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil, - double aScale, bool aMirror ) -{ - wxASSERT( !outputFile ); - m_plotMirror = aMirror; - plotOffset = aOffset; - plotScale = aScale; - m_IUsPerDecimil = aIusPerDecimil; - iuPerDeviceUnit = 1.0 / aIusPerDecimil; - /* Compute the paper size in IUs */ - paperSize = pageInfo.GetSizeMils(); - paperSize.x *= 10.0 * aIusPerDecimil; - paperSize.y *= 10.0 * aIusPerDecimil; - SetDefaultLineWidth( 100 * aIusPerDecimil ); // arbitrary default -} - - -/** This is the core for postscript/PDF text alignment - * It computes the transformation matrix to generate a user space - * system aligned with the text. Even the PS uses the concat - * operator to simplify PDF generation (concat is everything PDF - * has to modify the CTM. Lots of parameters, both in and out. - */ -void PSLIKE_PLOTTER::computeTextParameters( const wxPoint& aPos, - const wxString& aText, - int aOrient, - const wxSize& aSize, - bool aMirror, - enum EDA_TEXT_HJUSTIFY_T aH_justify, - enum EDA_TEXT_VJUSTIFY_T aV_justify, - int aWidth, - bool aItalic, - bool aBold, - double *wideningFactor, - double *ctm_a, - double *ctm_b, - double *ctm_c, - double *ctm_d, - double *ctm_e, - double *ctm_f, - double *heightFactor ) -{ - // Compute the starting position (compensated for alignment) - wxPoint start_pos = aPos; - - // This is an approximation of the text bounds (in IUs) - int tw = returnPostscriptTextWidth( aText, aSize.x, aItalic, aWidth ); - int th = aSize.y; - int dx, dy; - - switch( aH_justify ) - { - case GR_TEXT_HJUSTIFY_CENTER: - dx = -tw / 2; - break; - - case GR_TEXT_HJUSTIFY_RIGHT: - dx = -tw; - break; - - case GR_TEXT_HJUSTIFY_LEFT: - dx = 0; - break; - } - - switch( aV_justify ) - { - case GR_TEXT_VJUSTIFY_CENTER: - dy = th / 2; - break; - - case GR_TEXT_VJUSTIFY_TOP: - dy = th; - break; - - case GR_TEXT_VJUSTIFY_BOTTOM: - dy = 0; - break; - } - - RotatePoint( &dx, &dy, aOrient ); - RotatePoint( &tw, &th, aOrient ); - start_pos.x += dx; - start_pos.y += dy; - DPOINT pos_dev = userToDeviceCoordinates( start_pos ); - DPOINT sz_dev = userToDeviceSize( aSize ); - - // Now returns the final values... the widening factor - *wideningFactor = sz_dev.x / sz_dev.y; - - // Mirrored texts must be plotted as mirrored! - if( m_plotMirror ) - { - *wideningFactor = -*wideningFactor; - aOrient = -aOrient; - } - - // The CTM transformation matrix - double alpha = DECIDEG2RAD( aOrient ); - double sinalpha = sin( alpha ); - double cosalpha = cos( alpha ); - - *ctm_a = cosalpha; - *ctm_b = sinalpha; - *ctm_c = -sinalpha; - *ctm_d = cosalpha; - *ctm_e = pos_dev.x; - *ctm_f = pos_dev.y; - - // This is because the letters are less than 1 unit high - *heightFactor = sz_dev.y / postscriptTextAscent; -} - - -/* Set the current line width (in IUs) for the next plot - */ -void PS_PLOTTER::SetCurrentLineWidth( int width, void* aData ) -{ - wxASSERT( outputFile ); - int pen_width; - - if( width >= 0 ) - pen_width = width; - else - pen_width = defaultPenWidth; - - if( pen_width != GetCurrentLineWidth() ) - fprintf( outputFile, "%g setlinewidth\n", userToDeviceSize( pen_width ) ); - - currentPenWidth = pen_width; -} - - -void PS_PLOTTER::emitSetRGBColor( double r, double g, double b ) -{ - wxASSERT( outputFile ); - - // XXX why %.3g ? shouldn't %g suffice? who cares... - fprintf( outputFile, "%.3g %.3g %.3g setrgbcolor\n", r, g, b ); -} - - -/** - * Postscript supports dashed lines - */ -void PS_PLOTTER::SetDash( int dashed ) -{ - switch( dashed ) - { - case PLOTDASHTYPE_DASH: - fprintf( outputFile, "[%d %d] 0 setdash\n", - (int) GetDashMarkLenIU(), (int) GetDashGapLenIU() ); - break; - case PLOTDASHTYPE_DOT: - fprintf( outputFile, "[%d %d] 0 setdash\n", - (int) GetDotMarkLenIU(), (int) GetDashGapLenIU() ); - break; - case PLOTDASHTYPE_DASHDOT: - fprintf( outputFile, "[%d %d %d %d] 0 setdash\n", - (int) GetDashMarkLenIU(), (int) GetDashGapLenIU(), - (int) GetDotMarkLenIU(), (int) GetDashGapLenIU() ); - break; - default: - fputs( "solidline\n", outputFile ); - } -} - - -void PS_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width ) -{ - DPOINT p1_dev = userToDeviceCoordinates( p1 ); - DPOINT p2_dev = userToDeviceCoordinates( p2 ); - - SetCurrentLineWidth( width ); - fprintf( outputFile, "%g %g %g %g rect%d\n", p1_dev.x, p1_dev.y, - p2_dev.x - p1_dev.x, p2_dev.y - p1_dev.y, fill ); -} - - -void PS_PLOTTER::Circle( const wxPoint& pos, int diametre, FILL_T fill, int width ) -{ - wxASSERT( outputFile ); - DPOINT pos_dev = userToDeviceCoordinates( pos ); - double radius = userToDeviceSize( diametre / 2.0 ); - - SetCurrentLineWidth( width ); - fprintf( outputFile, "%g %g %g cir%d\n", pos_dev.x, pos_dev.y, radius, fill ); -} - - -void PS_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, - int radius, FILL_T fill, int width ) -{ - wxASSERT( outputFile ); - if( radius <= 0 ) - return; - - if( StAngle > EndAngle ) - std::swap( StAngle, EndAngle ); - - SetCurrentLineWidth( width ); - - // Calculate start point. - DPOINT centre_dev = userToDeviceCoordinates( centre ); - double radius_dev = userToDeviceSize( radius ); - - if( m_plotMirror ) - { - if( m_mirrorIsHorizontal ) - { - StAngle = 1800.0 -StAngle; - EndAngle = 1800.0 -EndAngle; - std::swap( StAngle, EndAngle ); - } - else - { - StAngle = -StAngle; - EndAngle = -EndAngle; - } - } - - fprintf( outputFile, "%g %g %g %g %g arc%d\n", centre_dev.x, centre_dev.y, - radius_dev, StAngle / 10.0, EndAngle / 10.0, fill ); -} - - -void PS_PLOTTER::PlotPoly( const std::vector< wxPoint >& aCornerList, - FILL_T aFill, int aWidth, void * aData ) -{ - if( aCornerList.size() <= 1 ) - return; - - SetCurrentLineWidth( aWidth ); - - DPOINT pos = userToDeviceCoordinates( aCornerList[0] ); - fprintf( outputFile, "newpath\n%g %g moveto\n", pos.x, pos.y ); - - for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) - { - pos = userToDeviceCoordinates( aCornerList[ii] ); - fprintf( outputFile, "%g %g lineto\n", pos.x, pos.y ); - } - - // Close/(fill) the path - fprintf( outputFile, "poly%d\n", aFill ); -} - - -/** - * Postscript-likes at the moment are the only plot engines supporting bitmaps... - */ -void PS_PLOTTER::PlotImage( const wxImage & aImage, const wxPoint& aPos, - double aScaleFactor ) -{ - wxSize pix_size; // size of the bitmap in pixels - pix_size.x = aImage.GetWidth(); - pix_size.y = aImage.GetHeight(); - DPOINT drawsize( aScaleFactor * pix_size.x, - aScaleFactor * pix_size.y ); // requested size of image - - // calculate the bottom left corner position of bitmap - wxPoint start = aPos; - start.x -= drawsize.x / 2; // left - start.y += drawsize.y / 2; // bottom (Y axis reversed) - - // calculate the top right corner position of bitmap - wxPoint end; - end.x = start.x + drawsize.x; - end.y = start.y - drawsize.y; - - fprintf( outputFile, "/origstate save def\n" ); - fprintf( outputFile, "/pix %d string def\n", pix_size.x ); - - // Locate lower-left corner of image - DPOINT start_dev = userToDeviceCoordinates( start ); - fprintf( outputFile, "%g %g translate\n", start_dev.x, start_dev.y ); - // Map image size to device - DPOINT end_dev = userToDeviceCoordinates( end ); - fprintf( outputFile, "%g %g scale\n", - std::abs(end_dev.x - start_dev.x), std::abs(end_dev.y - start_dev.y)); - - // Dimensions of source image (in pixels - fprintf( outputFile, "%d %d 8", pix_size.x, pix_size.y ); - // Map unit square to source - fprintf( outputFile, " [%d 0 0 %d 0 %d]\n", pix_size.x, -pix_size.y , pix_size.y); - // include image data in ps file - fprintf( outputFile, "{currentfile pix readhexstring pop}\n" ); - - if( colorMode ) - fputs( "false 3 colorimage\n", outputFile ); - else - fputs( "image\n", outputFile ); - // Single data source, 3 colors, Output RGB data (hexadecimal) - // (or the same downscaled to gray) - int jj = 0; - - for( int yy = 0; yy < pix_size.y; yy ++ ) - { - for( int xx = 0; xx < pix_size.x; xx++, jj++ ) - { - if( jj >= 16 ) - { - jj = 0; - fprintf( outputFile, "\n"); - } - - int red, green, blue; - red = aImage.GetRed( xx, yy) & 0xFF; - green = aImage.GetGreen( xx, yy) & 0xFF; - blue = aImage.GetBlue( xx, yy) & 0xFF; - - if( colorMode ) - fprintf( outputFile, "%2.2X%2.2X%2.2X", red, green, blue ); - else - fprintf( outputFile, "%2.2X", (red + green + blue) / 3 ); - } - } - - fprintf( outputFile, "\n"); - fprintf( outputFile, "origstate restore\n" ); -} - - -void PS_PLOTTER::PenTo( const wxPoint& pos, char plume ) -{ - wxASSERT( outputFile ); - - if( plume == 'Z' ) - { - if( penState != 'Z' ) - { - fputs( "stroke\n", outputFile ); - penState = 'Z'; - penLastpos.x = -1; - penLastpos.y = -1; - } - - return; - } - - if( penState == 'Z' ) - { - fputs( "newpath\n", outputFile ); - } - - if( penState != plume || pos != penLastpos ) - { - DPOINT pos_dev = userToDeviceCoordinates( pos ); - fprintf( outputFile, "%g %g %sto\n", - pos_dev.x, pos_dev.y, - ( plume=='D' ) ? "line" : "move" ); - } - - penState = plume; - penLastpos = pos; -} - - -/** - * The code within this function (and the CloseFilePS function) - * creates postscript files whose contents comply with Adobe's - * Document Structuring Convention, as documented by assorted - * details described within the following URLs: - * - * http://en.wikipedia.org/wiki/Document_Structuring_Conventions - * http://partners.adobe.com/public/developer/en/ps/5001.DSC_Spec.pdf - * - * - * BBox is the boundary box (position and size of the "client rectangle" - * for drawings (page - margins) in mils (0.001 inch) - */ -bool PS_PLOTTER::StartPlot() -{ - wxASSERT( outputFile ); - wxString msg; - - static const char* PSMacro[] = - { - "%%BeginProlog\n", - "/line { newpath moveto lineto stroke } bind def\n", - "/cir0 { newpath 0 360 arc stroke } bind def\n", - "/cir1 { newpath 0 360 arc gsave fill grestore stroke } bind def\n", - "/cir2 { newpath 0 360 arc gsave fill grestore stroke } bind def\n", - "/arc0 { newpath arc stroke } bind def\n", - "/arc1 { newpath 4 index 4 index moveto arc closepath gsave fill\n", - " grestore stroke } bind def\n", - "/arc2 { newpath 4 index 4 index moveto arc closepath gsave fill\n", - " grestore stroke } bind def\n", - "/poly0 { stroke } bind def\n", - "/poly1 { closepath gsave fill grestore stroke } bind def\n", - "/poly2 { closepath gsave fill grestore stroke } bind def\n", - "/rect0 { rectstroke } bind def\n", - "/rect1 { rectfill } bind def\n", - "/rect2 { rectfill } bind def\n", - "/linemode0 { 0 setlinecap 0 setlinejoin 0 setlinewidth } bind def\n", - "/linemode1 { 1 setlinecap 1 setlinejoin } bind def\n", - "/dashedline { [200] 100 setdash } bind def\n", - "/solidline { [] 0 setdash } bind def\n", - - // This is for 'hidden' text (search anchors for PDF) - "/phantomshow { moveto\n", - " /KicadFont findfont 0.000001 scalefont setfont\n", - " show } bind def\n", - - // This is for regular postscript text - "/textshow { gsave\n", - " findfont exch scalefont setfont concat 1 scale 0 0 moveto show\n", - " } bind def\n", - - // Utility for getting Latin1 encoded fonts - "/reencodefont {\n", - " findfont dup length dict begin\n", - " { 1 index /FID ne\n", - " { def }\n", - " { pop pop } ifelse\n", - " } forall\n", - " /Encoding ISOLatin1Encoding def\n", - " currentdict\n", - " end } bind def\n" - - // Remap AdobeStandard fonts to Latin1 - "/KicadFont /Helvetica reencodefont definefont pop\n", - "/KicadFont-Bold /Helvetica-Bold reencodefont definefont pop\n", - "/KicadFont-Oblique /Helvetica-Oblique reencodefont definefont pop\n", - "/KicadFont-BoldOblique /Helvetica-BoldOblique reencodefont definefont pop\n", - "%%EndProlog\n", - NULL - }; - - time_t time1970 = time( NULL ); - - fputs( "%!PS-Adobe-3.0\n", outputFile ); // Print header - - fprintf( outputFile, "%%%%Creator: %s\n", TO_UTF8( creator ) ); - - /* A "newline" character ("\n") is not included in the following string, - because it is provided by the ctime() function. */ - fprintf( outputFile, "%%%%CreationDate: %s", ctime( &time1970 ) ); - fprintf( outputFile, "%%%%Title: %s\n", TO_UTF8( filename ) ); - fprintf( outputFile, "%%%%Pages: 1\n" ); - fprintf( outputFile, "%%%%PageOrder: Ascend\n" ); - - // Print boundary box in 1/72 pixels per inch, box is in mils - const double BIGPTsPERMIL = 0.072; - - /* The coordinates of the lower left corner of the boundary - box need to be "rounded down", but the coordinates of its - upper right corner need to be "rounded up" instead. */ - wxSize psPaperSize = pageInfo.GetSizeMils(); - - if( !pageInfo.IsPortrait() ) - psPaperSize.Set( pageInfo.GetHeightMils(), pageInfo.GetWidthMils() ); - - fprintf( outputFile, "%%%%BoundingBox: 0 0 %d %d\n", - (int) ceil( psPaperSize.x * BIGPTsPERMIL ), - (int) ceil( psPaperSize.y * BIGPTsPERMIL ) ); - - // Specify the size of the sheet and the name associated with that size. - // (If the "User size" option has been selected for the sheet size, - // identify the sheet size as "Custom" (rather than as "User"), but - // otherwise use the name assigned by KiCad for each sheet size.) - // - // (The Document Structuring Convention also supports sheet weight, - // sheet color, and sheet type properties being specified within a - // %%DocumentMedia comment, but they are not being specified here; - // a zero and two null strings are subsequently provided instead.) - // - // (NOTE: m_Size.y is *supposed* to be listed before m_Size.x; - // the order in which they are specified is not wrong!) - // Also note pageSize is given in mils, not in internal units and must be - // converted to internal units. - - if( pageInfo.IsCustom() ) - fprintf( outputFile, "%%%%DocumentMedia: Custom %d %d 0 () ()\n", - KiROUND( psPaperSize.x * BIGPTsPERMIL ), - KiROUND( psPaperSize.y * BIGPTsPERMIL ) ); - - else // a standard paper size - fprintf( outputFile, "%%%%DocumentMedia: %s %d %d 0 () ()\n", - TO_UTF8( pageInfo.GetType() ), - KiROUND( psPaperSize.x * BIGPTsPERMIL ), - KiROUND( psPaperSize.y * BIGPTsPERMIL ) ); - - if( pageInfo.IsPortrait() ) - fprintf( outputFile, "%%%%Orientation: Portrait\n" ); - else - fprintf( outputFile, "%%%%Orientation: Landscape\n" ); - - fprintf( outputFile, "%%%%EndComments\n" ); - - // Now specify various other details. - - for( int ii = 0; PSMacro[ii] != NULL; ii++ ) - { - fputs( PSMacro[ii], outputFile ); - } - - // The following string has been specified here (rather than within - // PSMacro[]) to highlight that it has been provided to ensure that the - // contents of the postscript file comply with the details specified - // within the Document Structuring Convention. - fputs( "%%Page: 1 1\n" - "%%BeginPageSetup\n" - "gsave\n" - "0.0072 0.0072 scale\n" // Configure postscript for decimils coordinates - "linemode1\n", outputFile ); - - - // Rototranslate the coordinate to achieve the landscape layout - if( !pageInfo.IsPortrait() ) - fprintf( outputFile, "%d 0 translate 90 rotate\n", 10 * psPaperSize.x ); - - // Apply the user fine scale adjustments - if( plotScaleAdjX != 1.0 || plotScaleAdjY != 1.0 ) - fprintf( outputFile, "%g %g scale\n", - plotScaleAdjX, plotScaleAdjY ); - - // Set default line width - fprintf( outputFile, "%g setlinewidth\n", userToDeviceSize( defaultPenWidth ) ); - fputs( "%%EndPageSetup\n", outputFile ); - - return true; -} - - -bool PS_PLOTTER::EndPlot() -{ - wxASSERT( outputFile ); - fputs( "showpage\n" - "grestore\n" - "%%EOF\n", outputFile ); - fclose( outputFile ); - outputFile = NULL; - - return true; -} - - - -void PS_PLOTTER::Text( const wxPoint& aPos, - const COLOR4D aColor, - const wxString& aText, - double aOrient, - const wxSize& aSize, - enum EDA_TEXT_HJUSTIFY_T aH_justify, - enum EDA_TEXT_VJUSTIFY_T aV_justify, - int aWidth, - bool aItalic, - bool aBold, - bool aMultilineAllowed, - void* aData ) -{ - SetCurrentLineWidth( aWidth ); - SetColor( aColor ); - - // Fix me: see how to use PS text mode for multiline texts - if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) ) - aMultilineAllowed = false; // the text has only one line. - - // Draw the native postscript text (if requested) - // Currently: does not work: disable it - bool use_native = false; // = m_textMode == PLOTTEXTMODE_NATIVE && !aMultilineAllowed; - - if( use_native ) - { - const char *fontname = aItalic ? (aBold ? "/KicadFont-BoldOblique" - : "/KicadFont-Oblique") - : (aBold ? "/KicadFont-Bold" - : "/KicadFont"); - - // Compute the copious tranformation parameters - double ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f; - double wideningFactor, heightFactor; - computeTextParameters( aPos, aText, aOrient, aSize, m_plotMirror, aH_justify, - aV_justify, aWidth, aItalic, aBold, - &wideningFactor, &ctm_a, &ctm_b, &ctm_c, - &ctm_d, &ctm_e, &ctm_f, &heightFactor ); - - - // The text must be escaped correctly, the others are the various - // parameters. The CTM is formatted with %f since sin/cos tends - // to make %g use exponential notation (which is not supported) - fputsPostscriptString( outputFile, aText ); - fprintf( outputFile, " %g [%f %f %f %f %f %f] %g %s textshow\n", - wideningFactor, ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f, - heightFactor, fontname ); - - /* The textshow operator retained the coordinate system, we use it - * to plot the overbars. See the PDF sister function for more - * details */ - - std::vector pos_pairs; - postscriptOverlinePositions( aText, aSize.x, aItalic, aBold, &pos_pairs ); - int overbar_y = KiROUND( aSize.y * 1.1 ); - - for( unsigned i = 0; i < pos_pairs.size(); i += 2) - { - DPOINT dev_from = userToDeviceSize( wxSize( pos_pairs[i], overbar_y ) ); - DPOINT dev_to = userToDeviceSize( wxSize( pos_pairs[i + 1], overbar_y ) ); - fprintf( outputFile, "%g %g %g %g line ", - dev_from.x, dev_from.y, dev_to.x, dev_to.y ); - } - - // Restore the CTM - fputs( "grestore\n", outputFile ); - } - - // Draw the hidden postscript text (if requested) - if( m_textMode == PLOTTEXTMODE_PHANTOM ) - { - fputsPostscriptString( outputFile, aText ); - DPOINT pos_dev = userToDeviceCoordinates( aPos ); - fprintf( outputFile, " %g %g phantomshow\n", pos_dev.x, pos_dev.y ); - } - - // Draw the stroked text (if requested) - if( !use_native ) - { - PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify, - aWidth, aItalic, aBold, aMultilineAllowed ); - } -} - - -/** - * Character widths for Helvetica - */ -const double hv_widths[256] = { - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.355, 0.556, 0.556, 0.889, 0.667, 0.191, - 0.333, 0.333, 0.389, 0.584, 0.278, 0.333, 0.278, 0.278, - 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, - 0.556, 0.556, 0.278, 0.278, 0.584, 0.584, 0.584, 0.556, - 1.015, 0.667, 0.667, 0.722, 0.722, 0.667, 0.611, 0.778, - 0.722, 0.278, 0.500, 0.667, 0.556, 0.833, 0.722, 0.778, - 0.667, 0.778, 0.722, 0.667, 0.611, 0.722, 0.667, 0.944, - 0.667, 0.667, 0.611, 0.278, 0.278, 0.278, 0.469, 0.556, - 0.333, 0.556, 0.556, 0.500, 0.556, 0.556, 0.278, 0.556, - 0.556, 0.222, 0.222, 0.500, 0.222, 0.833, 0.556, 0.556, - 0.556, 0.556, 0.333, 0.500, 0.278, 0.556, 0.500, 0.722, - 0.500, 0.500, 0.500, 0.334, 0.260, 0.334, 0.584, 0.278, - 0.278, 0.278, 0.222, 0.556, 0.333, 1.000, 0.556, 0.556, - 0.333, 1.000, 0.667, 0.333, 1.000, 0.278, 0.278, 0.278, - 0.278, 0.222, 0.222, 0.333, 0.333, 0.350, 0.556, 1.000, - 0.333, 1.000, 0.500, 0.333, 0.944, 0.278, 0.278, 0.667, - 0.278, 0.333, 0.556, 0.556, 0.556, 0.556, 0.260, 0.556, - 0.333, 0.737, 0.370, 0.556, 0.584, 0.333, 0.737, 0.333, - 0.400, 0.584, 0.333, 0.333, 0.333, 0.556, 0.537, 0.278, - 0.333, 0.333, 0.365, 0.556, 0.834, 0.834, 0.834, 0.611, - 0.667, 0.667, 0.667, 0.667, 0.667, 0.667, 1.000, 0.722, - 0.667, 0.667, 0.667, 0.667, 0.278, 0.278, 0.278, 0.278, - 0.722, 0.722, 0.778, 0.778, 0.778, 0.778, 0.778, 0.584, - 0.778, 0.722, 0.722, 0.722, 0.722, 0.667, 0.667, 0.611, - 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.889, 0.500, - 0.556, 0.556, 0.556, 0.556, 0.278, 0.278, 0.278, 0.278, - 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.584, - 0.611, 0.556, 0.556, 0.556, 0.556, 0.500, 0.556, 0.500 -}; - -/** - * Character widths for Helvetica-Bold - */ -const double hvb_widths[256] = { - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.333, 0.474, 0.556, 0.556, 0.889, 0.722, 0.238, - 0.333, 0.333, 0.389, 0.584, 0.278, 0.333, 0.278, 0.278, - 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, - 0.556, 0.556, 0.333, 0.333, 0.584, 0.584, 0.584, 0.611, - 0.975, 0.722, 0.722, 0.722, 0.722, 0.667, 0.611, 0.778, - 0.722, 0.278, 0.556, 0.722, 0.611, 0.833, 0.722, 0.778, - 0.667, 0.778, 0.722, 0.667, 0.611, 0.722, 0.667, 0.944, - 0.667, 0.667, 0.611, 0.333, 0.278, 0.333, 0.584, 0.556, - 0.333, 0.556, 0.611, 0.556, 0.611, 0.556, 0.333, 0.611, - 0.611, 0.278, 0.278, 0.556, 0.278, 0.889, 0.611, 0.611, - 0.611, 0.611, 0.389, 0.556, 0.333, 0.611, 0.556, 0.778, - 0.556, 0.556, 0.500, 0.389, 0.280, 0.389, 0.584, 0.278, - 0.278, 0.278, 0.278, 0.556, 0.500, 1.000, 0.556, 0.556, - 0.333, 1.000, 0.667, 0.333, 1.000, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.500, 0.500, 0.350, 0.556, 1.000, - 0.333, 1.000, 0.556, 0.333, 0.944, 0.278, 0.278, 0.667, - 0.278, 0.333, 0.556, 0.556, 0.556, 0.556, 0.280, 0.556, - 0.333, 0.737, 0.370, 0.556, 0.584, 0.333, 0.737, 0.333, - 0.400, 0.584, 0.333, 0.333, 0.333, 0.611, 0.556, 0.278, - 0.333, 0.333, 0.365, 0.556, 0.834, 0.834, 0.834, 0.611, - 0.722, 0.722, 0.722, 0.722, 0.722, 0.722, 1.000, 0.722, - 0.667, 0.667, 0.667, 0.667, 0.278, 0.278, 0.278, 0.278, - 0.722, 0.722, 0.778, 0.778, 0.778, 0.778, 0.778, 0.584, - 0.778, 0.722, 0.722, 0.722, 0.722, 0.667, 0.667, 0.611, - 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.889, 0.556, - 0.556, 0.556, 0.556, 0.556, 0.278, 0.278, 0.278, 0.278, - 0.611, 0.611, 0.611, 0.611, 0.611, 0.611, 0.611, 0.584, - 0.611, 0.611, 0.611, 0.611, 0.611, 0.556, 0.611, 0.556 -}; - -/** - * Character widths for Helvetica-Oblique - */ -const double hvo_widths[256] = { - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.355, 0.556, 0.556, 0.889, 0.667, 0.191, - 0.333, 0.333, 0.389, 0.584, 0.278, 0.333, 0.278, 0.278, - 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, - 0.556, 0.556, 0.278, 0.278, 0.584, 0.584, 0.584, 0.556, - 1.015, 0.667, 0.667, 0.722, 0.722, 0.667, 0.611, 0.778, - 0.722, 0.278, 0.500, 0.667, 0.556, 0.833, 0.722, 0.778, - 0.667, 0.778, 0.722, 0.667, 0.611, 0.722, 0.667, 0.944, - 0.667, 0.667, 0.611, 0.278, 0.278, 0.278, 0.469, 0.556, - 0.333, 0.556, 0.556, 0.500, 0.556, 0.556, 0.278, 0.556, - 0.556, 0.222, 0.222, 0.500, 0.222, 0.833, 0.556, 0.556, - 0.556, 0.556, 0.333, 0.500, 0.278, 0.556, 0.500, 0.722, - 0.500, 0.500, 0.500, 0.334, 0.260, 0.334, 0.584, 0.278, - 0.278, 0.278, 0.222, 0.556, 0.333, 1.000, 0.556, 0.556, - 0.333, 1.000, 0.667, 0.333, 1.000, 0.278, 0.278, 0.278, - 0.278, 0.222, 0.222, 0.333, 0.333, 0.350, 0.556, 1.000, - 0.333, 1.000, 0.500, 0.333, 0.944, 0.278, 0.278, 0.667, - 0.278, 0.333, 0.556, 0.556, 0.556, 0.556, 0.260, 0.556, - 0.333, 0.737, 0.370, 0.556, 0.584, 0.333, 0.737, 0.333, - 0.400, 0.584, 0.333, 0.333, 0.333, 0.556, 0.537, 0.278, - 0.333, 0.333, 0.365, 0.556, 0.834, 0.834, 0.834, 0.611, - 0.667, 0.667, 0.667, 0.667, 0.667, 0.667, 1.000, 0.722, - 0.667, 0.667, 0.667, 0.667, 0.278, 0.278, 0.278, 0.278, - 0.722, 0.722, 0.778, 0.778, 0.778, 0.778, 0.778, 0.584, - 0.778, 0.722, 0.722, 0.722, 0.722, 0.667, 0.667, 0.611, - 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.889, 0.500, - 0.556, 0.556, 0.556, 0.556, 0.278, 0.278, 0.278, 0.278, - 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.584, - 0.611, 0.556, 0.556, 0.556, 0.556, 0.500, 0.556, 0.500 -}; - -/** - * Character widths for Helvetica-BoldOblique - */ -const double hvbo_widths[256] = { - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, 0.278, - 0.278, 0.333, 0.474, 0.556, 0.556, 0.889, 0.722, 0.238, - 0.333, 0.333, 0.389, 0.584, 0.278, 0.333, 0.278, 0.278, - 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, - 0.556, 0.556, 0.333, 0.333, 0.584, 0.584, 0.584, 0.611, - 0.975, 0.722, 0.722, 0.722, 0.722, 0.667, 0.611, 0.778, - 0.722, 0.278, 0.556, 0.722, 0.611, 0.833, 0.722, 0.778, - 0.667, 0.778, 0.722, 0.667, 0.611, 0.722, 0.667, 0.944, - 0.667, 0.667, 0.611, 0.333, 0.278, 0.333, 0.584, 0.556, - 0.333, 0.556, 0.611, 0.556, 0.611, 0.556, 0.333, 0.611, - 0.611, 0.278, 0.278, 0.556, 0.278, 0.889, 0.611, 0.611, - 0.611, 0.611, 0.389, 0.556, 0.333, 0.611, 0.556, 0.778, - 0.556, 0.556, 0.500, 0.389, 0.280, 0.389, 0.584, 0.278, - 0.278, 0.278, 0.278, 0.556, 0.500, 1.000, 0.556, 0.556, - 0.333, 1.000, 0.667, 0.333, 1.000, 0.278, 0.278, 0.278, - 0.278, 0.278, 0.278, 0.500, 0.500, 0.350, 0.556, 1.000, - 0.333, 1.000, 0.556, 0.333, 0.944, 0.278, 0.278, 0.667, - 0.278, 0.333, 0.556, 0.556, 0.556, 0.556, 0.280, 0.556, - 0.333, 0.737, 0.370, 0.556, 0.584, 0.333, 0.737, 0.333, - 0.400, 0.584, 0.333, 0.333, 0.333, 0.611, 0.556, 0.278, - 0.333, 0.333, 0.365, 0.556, 0.834, 0.834, 0.834, 0.611, - 0.722, 0.722, 0.722, 0.722, 0.722, 0.722, 1.000, 0.722, - 0.667, 0.667, 0.667, 0.667, 0.278, 0.278, 0.278, 0.278, - 0.722, 0.722, 0.778, 0.778, 0.778, 0.778, 0.778, 0.584, - 0.778, 0.722, 0.722, 0.722, 0.722, 0.667, 0.667, 0.611, - 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.889, 0.556, - 0.556, 0.556, 0.556, 0.556, 0.278, 0.278, 0.278, 0.278, - 0.611, 0.611, 0.611, 0.611, 0.611, 0.611, 0.611, 0.584, - 0.611, 0.611, 0.611, 0.611, 0.611, 0.556, 0.611, 0.556 -}; diff --git a/common/plotters/common_plotSVG_functions.cpp b/common/plotters/common_plotSVG_functions.cpp deleted file mode 100644 index b8aacc3bc5..0000000000 --- a/common/plotters/common_plotSVG_functions.cpp +++ /dev/null @@ -1,645 +0,0 @@ -/** - * @file common_plotPS_functions.cpp - * @brief Kicad: Common plot SVG functions - */ - -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2017 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 - */ - -/* Some info on basic items SVG format, used here: - * The root element of all SVG files is the element. - * - * The element is used to group SVG shapes together. - * Once grouped you can transform the whole group of shapes as if it was a single shape. - * This is an advantage compared to a nested element - * which cannot be the target of transformation by itself. - * - * The element represents a rectangle. - * Using this element you can draw rectangles of various width, height, - * with different stroke (outline) and fill colors, with sharp or rounded corners etc. - * - * - * - * - * - * - * - * The element is used to draw circles. - * - * - * The element is used to draw ellipses. - * An ellipse is a circle that does not have equal height and width. - * Its radius in the x and y directions are different, in other words. - * - * - * The element is used to draw lines. - * - * - * - * - * The element is used to draw multiple connected lines - * Here is a simple example: - * - * - * - * The element is used to draw with multiple (3 or more) sides / edges. - * Here is a simple example: - * - * - * - * The element is used to draw advanced shapes combined from lines and arcs, - * with or without fill. - * It is probably the most advanced and versatile SVG shape of them all. - * It is probably also the hardest element to master. - * - * - * Draw an elliptic arc: it is one of basic path command: - * - * flag_arc_large: 0 = small arc > 180 deg, 1 = large arc > 180 deg - * flag_sweep : 0 = CCW, 1 = CW - * The center of ellipse is automatically calculated. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -/** - * Function XmlEsc - * translates '<' to "<", '>' to ">" and so on, according to the spec: - * http://www.w3.org/TR/2000/WD-xml-c14n-20000119.html#charescaping - * May be moved to a library if needed generally, but not expecting that. - */ -static wxString XmlEsc( const wxString& aStr, bool isAttribute = false ) -{ - wxString escaped; - - escaped.reserve( aStr.length() ); - - for( wxString::const_iterator it = aStr.begin(); it != aStr.end(); ++it ) - { - const wxChar c = *it; - - switch( c ) - { - case wxS( '<' ): - escaped.append( wxS( "<" ) ); - break; - case wxS( '>' ): - escaped.append( wxS( ">" ) ); - break; - case wxS( '&' ): - escaped.append( wxS( "&" ) ); - break; - case wxS( '\r' ): - escaped.append( wxS( " " ) ); - break; - default: - if( isAttribute ) - { - switch( c ) - { - case wxS( '"' ): - escaped.append( wxS( """ ) ); - break; - case wxS( '\t' ): - escaped.append( wxS( " " ) ); - break; - case wxS( '\n' ): - escaped.append( wxS( " " )); - break; - default: - escaped.append(c); - } - } - else - escaped.append(c); - } - } - - return escaped; -} - - -SVG_PLOTTER::SVG_PLOTTER() -{ - m_graphics_changed = true; - SetTextMode( PLOTTEXTMODE_STROKE ); - m_fillMode = NO_FILL; // or FILLED_SHAPE or FILLED_WITH_BG_BODYCOLOR - m_pen_rgb_color = 0; // current color value (black) - m_brush_rgb_color = 0; // current color value (black) - m_dashed = false; -} - - -void SVG_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil, - double aScale, bool aMirror ) -{ - m_plotMirror = aMirror; - m_yaxisReversed = true; // unlike other plotters, SVG has Y axis reversed - plotOffset = aOffset; - plotScale = aScale; - m_IUsPerDecimil = aIusPerDecimil; - iuPerDeviceUnit = 1.0 / aIusPerDecimil; - /* Compute the paper size in IUs */ - paperSize = pageInfo.GetSizeMils(); - paperSize.x *= 10.0 * aIusPerDecimil; - paperSize.y *= 10.0 * aIusPerDecimil; - SetDefaultLineWidth( 100 * aIusPerDecimil ); // arbitrary default -} - - -void SVG_PLOTTER::SetColor( COLOR4D color ) -{ - PSLIKE_PLOTTER::SetColor( color ); - - if( m_graphics_changed ) - setSVGPlotStyle(); -} - - -void SVG_PLOTTER::setFillMode( FILL_T fill ) -{ - if( m_fillMode != fill ) - { - m_graphics_changed = true; - m_fillMode = fill; - } -} - - -void SVG_PLOTTER::setSVGPlotStyle() -{ - fputs( "\n\n", outputFile ); - - m_graphics_changed = false; -} - -/* Set the current line width (in IUs) for the next plot - */ -void SVG_PLOTTER::SetCurrentLineWidth( int width, void* aData ) -{ - int pen_width; - - if( width >= 0 ) - pen_width = width; - else - pen_width = defaultPenWidth; - - if( pen_width != currentPenWidth ) - { - m_graphics_changed = true; - currentPenWidth = pen_width; - } - - if( m_graphics_changed ) - setSVGPlotStyle(); -} - - -/* initialize m_red, m_green, m_blue ( 0 ... 255) - * from reduced values r, g ,b ( 0.0 to 1.0 ) - */ -void SVG_PLOTTER::emitSetRGBColor( double r, double g, double b ) -{ - int red = (int) ( 255.0 * r ); - int green = (int) ( 255.0 * g ); - int blue = (int) ( 255.0 * b ); - long rgb_color = (red << 16) | (green << 8) | blue; - - if( m_pen_rgb_color != rgb_color ) - { - m_graphics_changed = true; - m_pen_rgb_color = rgb_color; - - // Currently, use the same color for brush and pen - // (i.e. to draw and fill a contour) - m_brush_rgb_color = rgb_color; - } -} - - -/** - * SVG supports dashed lines - */ -void SVG_PLOTTER::SetDash( int dashed ) -{ - if( m_dashed != dashed ) - { - m_graphics_changed = true; - m_dashed = dashed; - } - - if( m_graphics_changed ) - setSVGPlotStyle(); -} - - -void SVG_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width ) -{ - EDA_RECT rect( p1, wxSize( p2.x -p1.x, p2.y -p1.y ) ); - rect.Normalize(); - DPOINT org_dev = userToDeviceCoordinates( rect.GetOrigin() ); - DPOINT end_dev = userToDeviceCoordinates( rect.GetEnd() ); - DSIZE size_dev = end_dev - org_dev; - // Ensure size of rect in device coordinates is > 0 - // I don't know if this is a SVG issue or a Inkscape issue, but - // Inkscape has problems with negative or null values for width and/or height, so avoid them - DBOX rect_dev( org_dev, size_dev); - rect_dev.Normalize(); - - setFillMode( fill ); - SetCurrentLineWidth( width ); - - // Rectangles having a 0 size value for height or width are just not drawn on Inscape, - // so use a line when happens. - if( rect_dev.GetSize().x == 0.0 || rect_dev.GetSize().y == 0.0 ) // Draw a line - fprintf( outputFile, - "\n", - rect_dev.GetPosition().x, rect_dev.GetPosition().y, - rect_dev.GetEnd().x, rect_dev.GetEnd().y - ); - - else - fprintf( outputFile, - "\n", - rect_dev.GetPosition().x, rect_dev.GetPosition().y, - rect_dev.GetSize().x, rect_dev.GetSize().y, - 0.0 // radius of rounded corners - ); -} - - -void SVG_PLOTTER::Circle( const wxPoint& pos, int diametre, FILL_T fill, int width ) -{ - DPOINT pos_dev = userToDeviceCoordinates( pos ); - double radius = userToDeviceSize( diametre / 2.0 ); - - setFillMode( fill ); - SetCurrentLineWidth( width ); - - fprintf( outputFile, - " \n", - pos_dev.x, pos_dev.y, radius ); -} - - -void SVG_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius, - FILL_T fill, int width ) -{ - /* Draws an arc of a circle, centred on (xc,yc), with starting point - * (x1, y1) and ending at (x2, y2). The current pen is used for the outline - * and the current brush for filling the shape. - * - * The arc is drawn in an anticlockwise direction from the start point to - * the end point - */ - - if( radius <= 0 ) - return; - - if( StAngle > EndAngle ) - std::swap( StAngle, EndAngle ); - - setFillMode( fill ); - SetCurrentLineWidth( width ); - - // Calculate start point. - DPOINT centre_dev = userToDeviceCoordinates( centre ); - double radius_dev = userToDeviceSize( radius ); - - if( !m_yaxisReversed ) // Should be never the case - { - double tmp = StAngle; - StAngle = -EndAngle; - EndAngle = -tmp; - } - - if( m_plotMirror ) - { - if( m_mirrorIsHorizontal ) - { - StAngle = 1800.0 -StAngle; - EndAngle = 1800.0 -EndAngle; - std::swap( StAngle, EndAngle ); - } - else - { - StAngle = -StAngle; - EndAngle = -EndAngle; - } - } - - DPOINT start; - start.x = radius_dev; - RotatePoint( &start.x, &start.y, StAngle ); - DPOINT end; - end.x = radius_dev; - RotatePoint( &end.x, &end.y, EndAngle ); - start += centre_dev; - end += centre_dev; - - double theta1 = DECIDEG2RAD( StAngle ); - - if( theta1 < 0 ) - theta1 = theta1 + M_PI * 2; - - double theta2 = DECIDEG2RAD( EndAngle ); - - if( theta2 < 0 ) - theta2 = theta2 + M_PI * 2; - - if( theta2 < theta1 ) - theta2 = theta2 + M_PI * 2; - - int flg_arc = 0; // flag for large or small arc. 0 means less than 180 degrees - - if( fabs( theta2 - theta1 ) > M_PI ) - flg_arc = 1; - - int flg_sweep = 0; // flag for sweep always 0 - - // Draw a single arc: an arc is one of 3 curve commands (2 other are 2 bezier curves) - // params are start point, radius1, radius2, X axe rotation, - // flag arc size (0 = small arc > 180 deg, 1 = large arc > 180 deg), - // sweep arc ( 0 = CCW, 1 = CW), - // end point - fprintf( outputFile, "\n", - start.x, start.y, radius_dev, radius_dev, - flg_arc, flg_sweep, - end.x, end.y ); -} - - -void SVG_PLOTTER::PlotPoly( const std::vector& aCornerList, - FILL_T aFill, int aWidth, void * aData ) -{ - if( aCornerList.size() <= 1 ) - return; - - setFillMode( aFill ); - SetCurrentLineWidth( aWidth ); - - switch( aFill ) - { - case NO_FILL: - fprintf( outputFile, " \n" ); -} - - -/** - * Postscript-likes at the moment are the only plot engines supporting bitmaps... - */ -void SVG_PLOTTER::PlotImage( const wxImage& aImage, const wxPoint& aPos, - double aScaleFactor ) -{ - // in svg file we must insert a link to a png image file to plot an image - // the image itself is not included in the svg file. - // So we prefer skip the image, and just draw a rectangle, - // like other plotters which do not support images - - PLOTTER::PlotImage( aImage, aPos, aScaleFactor ); - -} - - -void SVG_PLOTTER::PenTo( const wxPoint& pos, char plume ) -{ - if( plume == 'Z' ) - { - if( penState != 'Z' ) - { - fputs( "\" />\n", outputFile ); - penState = 'Z'; - penLastpos.x = -1; - penLastpos.y = -1; - } - - return; - } - - if( penState == 'Z' ) // here plume = 'D' or 'U' - { - DPOINT pos_dev = userToDeviceCoordinates( pos ); - - // Ensure we do not use a fill mode when moving tne pen, - // in SVG mode (i;e. we are plotting only basic lines, not a filled area - if( m_fillMode != NO_FILL ) - { - setFillMode( NO_FILL ); - setSVGPlotStyle(); - } - - fprintf( outputFile, "\n", - " \n", - "\n", - (double) paperSize.x / m_IUsPerDecimil * 2.54 / 10000, - (double) paperSize.y / m_IUsPerDecimil * 2.54 / 10000, - origin.x, origin.y, - (int) ( paperSize.x / m_IUsPerDecimil ), - (int) ( paperSize.y / m_IUsPerDecimil) ); - - // Write title - char date_buf[250]; - time_t ltime = time( NULL ); - strftime( date_buf, 250, "%Y/%m/%d %H:%M:%S", - localtime( <ime ) ); - - fprintf( outputFile, - "SVG Picture created as %s date %s \n", - TO_UTF8( XmlEsc( wxFileName( filename ).GetFullName() ) ), date_buf ); - // End of header - fprintf( outputFile, " Picture generated by %s \n", - TO_UTF8( XmlEsc( creator ) ) ); - - // output the pen and brush color (RVB values in hex) and opacity - double opacity = 1.0; // 0.0 (transparent to 1.0 (solid) - fprintf( outputFile, - "\n", outputFile ); - return true; -} - - -bool SVG_PLOTTER::EndPlot() -{ - fputs( " \n\n", outputFile ); - fclose( outputFile ); - outputFile = NULL; - - return true; -} - - -void SVG_PLOTTER::Text( const wxPoint& aPos, - const COLOR4D aColor, - const wxString& aText, - double aOrient, - const wxSize& aSize, - enum EDA_TEXT_HJUSTIFY_T aH_justify, - enum EDA_TEXT_VJUSTIFY_T aV_justify, - int aWidth, - bool aItalic, - bool aBold, - bool aMultilineAllowed, - void* aData ) -{ - setFillMode( NO_FILL ); - SetColor( aColor ); - SetCurrentLineWidth( aWidth ); - - // TODO: see if the postscript native text code can be used in SVG plotter - - PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify, - aWidth, aItalic, aBold, aMultilineAllowed ); -} diff --git a/common/class_plotter.cpp b/common/plotters/plotter.cpp similarity index 100% rename from common/class_plotter.cpp rename to common/plotters/plotter.cpp diff --git a/include/class_plotter.h b/include/plotter.h similarity index 100% rename from include/class_plotter.h rename to include/plotter.h