/* Plot round pad or via.
 */
void HPGL_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre,
                                   EDA_DRAW_MODE_T trace_mode )
{
    wxASSERT( outputFile );
    DPOINT  pos_dev = userToDeviceCoordinates( pos );

    int     delta   = KiROUND( penDiameter - penOverlap );
    int     radius  = ( diametre - KiROUND( penDiameter ) ) / 2;

    if( radius < 0 )
        radius = 0;

    double rsize = userToDeviceSize( radius );

    fprintf( outputFile, "PA %.0f,%.0f;CI %.0f;\n",
             pos_dev.x, pos_dev.y, rsize );

    if( trace_mode == FILLED )        // Plot in filled mode.
    {
        if( delta > 0 )
        {
            while( (radius -= delta ) >= 0 )
            {
                rsize = userToDeviceSize( radius );
                fprintf( outputFile, "PA %.0f,%.0f;CI %.0f;\n",
                         pos_dev.x, pos_dev.y, rsize );
            }
        }
    }

    PenFinish();
}
void SVG_PLOTTER::setSVGPlotStyle()
{
    fputs( "</g>\n<g style=\"", outputFile );
    fputs( "fill:#", outputFile );
    // output the background fill color
    fprintf( outputFile, "%6.6lX; ", m_brush_rgb_color );

    switch( m_fillMode )
    {
    case NO_FILL:
        fputs( "fill-opacity:0.0; ", outputFile );
        break;

    case FILLED_SHAPE:
        fputs( "fill-opacity:1.0; ", outputFile );
        break;

    case FILLED_WITH_BG_BODYCOLOR:
        fputs( "fill-opacity:0.6; ", outputFile );
        break;
    }

    double pen_w = userToDeviceSize( GetCurrentLineWidth() );
    fprintf( outputFile, "\nstroke:#%6.6lX; stroke-width:%g; stroke-opacity:1; \n",
             m_pen_rgb_color, pen_w  );
    fputs( "stroke-linecap:round; stroke-linejoin:round;\">\n", outputFile );

    m_graphics_changed = false;
}
/* 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( ColorGetName( 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 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( ColorGetName( 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");
        }
    }
}
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 )
        EXCHG( 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;
            EXCHG( 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::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 );
}
/**
 * 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;
}
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,
             "<circle cx=\"%g\" cy=\"%g\" r=\"%g\" /> \n",
             pos_dev.x, pos_dev.y, radius );
}
/**
 * HPGL circle: fill not supported
 */
void HPGL_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_T fill,
                           int width )
{
    wxASSERT( outputFile );
    double radius = userToDeviceSize( diameter / 2 );

    if( radius > 0 )
    {
        MoveTo( centre );
        fprintf( outputFile, "CI %g;\n", radius );
        PenFinish();
    }
}
/* 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;
}
/**
 * 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 default width (like -1)
 */
void PDF_PLOTTER::SetCurrentLineWidth( int width )
{
    wxASSERT( workFile );
    int pen_width;

    if( width > 0 )
        pen_width = width;
    else
        pen_width = defaultPenWidth;

    if( pen_width != currentPenWidth )
        fprintf( workFile, "%g w\n",
                 userToDeviceSize( pen_width ) );

    currentPenWidth = pen_width;
}
/**
 * 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' );
}
/**
 * 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 ) );
}
/* Plot round pad or via.
 */
void HPGL_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre,
                                   EDA_DRAW_MODE_T trace_mode )
{
    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();
}
// 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();
    }
}
/**
 * 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;
}
double PLOTTER::GetDashGapLenIU() const
{
    return userToDeviceSize( m_dashGapLength_mm*10000/25.4*m_IUsPerDecimil + GetCurrentLineWidth() );
}
double PLOTTER::GetDashMarkLenIU() const
{
    double mark = userToDeviceSize( m_dashMarkLength_mm*10000/25.4*m_IUsPerDecimil - GetCurrentLineWidth() );
    return ( mark < 0.0 ) ? 0.0 : mark;
}
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 )
{
    SetCurrentLineWidth( aWidth );
    SetColor( aColor );

    // Draw the native postscript text (if requested)
    if( m_textMode == PLOTTEXTMODE_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( m_textMode != PLOTTEXTMODE_NATIVE )
    {
        PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify,
                aWidth, aItalic, aBold );
    }
}
void DXF_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 )
{
    // 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 miltiline 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( ColorGetName( 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 );
    }
}
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 )
        EXCHG( 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;
            EXCHG( 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, "<path d=\"M%g %g A%g %g 0.0 %d %d %g %g \" />\n",
             start.x, start.y, radius_dev, radius_dev,
             flg_arc, flg_sweep,
             end.x, end.y  );
}
void PDF_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 )
{
    // 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)
    if( m_textMode != PLOTTEXTMODE_STROKE && !aMultilineAllowed )
    {
        const char *fontname = aItalic ? (aBold ? "/KicadFontBI" : "/KicadFontI")
            : (aBold ? "/KicadFontB" : "/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 );

        SetColor( aColor );
        SetCurrentLineWidth( aWidth );

        /* 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)
           Rendermode 0 shows the text, rendermode 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,
                (m_textMode == PLOTTEXTMODE_NATIVE) ? 0 : 3,
                wideningFactor * 100 );

        // The text must be escaped correctly
        fputsPostscriptString( workFile, aText );
        fputs( " Tj ET\n", workFile );

        /* We are still in text coordinates, plot the overbars (if we're
         * not doing phantom text) */
        if( m_textMode == PLOTTEXTMODE_NATIVE )
        {
            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)
            {
                /* 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( m_textMode != PLOTTEXTMODE_NATIVE || aMultilineAllowed )
    {
        PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify,
                aWidth, aItalic, aBold, aMultilineAllowed );
    }
}
/**
 * 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
}
/** 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;
}