diff options
Diffstat (limited to 'common/common_plotPS_functions.cpp')
-rw-r--r-- | common/common_plotPS_functions.cpp | 1090 |
1 files changed, 1090 insertions, 0 deletions
diff --git a/common/common_plotPS_functions.cpp b/common/common_plotPS_functions.cpp new file mode 100644 index 0000000..bbf9ede --- /dev/null +++ b/common/common_plotPS_functions.cpp @@ -0,0 +1,1090 @@ +/* + * 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 CHANGELOG.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 <fctsys.h> +#include <trigo.h> +#include <wxstruct.h> +#include <base_struct.h> +#include <common.h> +#include <plot_common.h> +#include <macros.h> +#include <kicad_string.h> + +/* 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( EDA_COLOR_T color ) +{ + // Return at invalid color index + if( color < 0 ) + return; + + if( colorMode ) + { + double r = g_ColorRefs[color].m_Red / 255.0; + double g = g_ColorRefs[color].m_Green / 255.0; + double b = g_ColorRefs[color].m_Blue / 255.0; + if( negativeMode ) + emitSetRGBColor( 1 - r, 1 - g, 1 - b ); + else + emitSetRGBColor( r, g, 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 != 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 ) +{ + 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 ); + else + sketchOval( aPadPos, size, aPadOrient, -1 ); +} + + +void PSLIKE_PLOTTER::FlashPadCircle( const wxPoint& aPadPos, int aDiameter, + EDA_DRAW_MODE_T aTraceMode ) +{ + 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 ) +{ + 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::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners, + double aPadOrient, EDA_DRAW_MODE_T aTraceMode ) +{ + 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<int> *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 ) +{ + 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, + 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.y / sz_dev.x; + + // 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 ) +{ + 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( bool dashed ) +{ + wxASSERT( outputFile ); + if( dashed ) + fprintf( outputFile, "[%d %d] 0 setdash\n", + (int) GetDashMarkLenIU(), (int) GetDashGapLenIU() ); + else + 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 ) +{ + 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, + enum EDA_COLOR_T 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 ) +{ + 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, 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<int> 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 +}; |