/* 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; }