/** * Common plot library \n * Plot settings, and plotting engines (Postscript, Gerber, HPGL and DXF) * * @file plot_common.h */ #ifndef PLOT_COMMON_H_ #define PLOT_COMMON_H_ #include #include #include #include // PAGE_INFO #include // FILL_T /** * Enum PlotFormat * is the set of supported output plot formats. They should be kept in order * of the radio buttons in the plot panel/windows. */ enum PlotFormat { PLOT_FORMAT_HPGL, PLOT_FORMAT_GERBER, PLOT_FORMAT_POST, PLOT_FORMAT_DXF, PLOT_FORMAT_PDF }; /** * Enum for choosing which kind of text to output with the PSLIKE * plotters. You can: * 1) only use the internal vector font * 2) only use native postscript fonts * 3) use the internal vector font and add 'phantom' text to aid * searching */ enum PostscriptTextMode { PSTEXTMODE_STROKE, PSTEXTMODE_NATIVE, PSTEXTMODE_PHANTOM }; /** * Base plotter engine class. General rule: all the interface with the caller * is done in IU, the IU size is specified with SetViewport. Internal and * output processing is usually done in decimils (or whatever unit the * effective engine class need to use) */ class PLOTTER { public: PLOTTER( ); virtual ~PLOTTER() { // Emergency cleanup if( outputFile ) { fclose( outputFile ); } } /** * Returns the effective plot engine in use. It's not very OO but for * now is required since some things are only done with some output devices * (like drill marks, emitted only for postscript */ virtual PlotFormat GetPlotterType() const = 0; virtual bool StartPlot( FILE* fout ) = 0; virtual bool EndPlot() = 0; virtual void SetNegative( bool _negative ) { negativeMode = _negative; } virtual void SetColorMode( bool _color_mode ) { colorMode = _color_mode; } bool GetColorMode() const { return colorMode; } virtual void SetPageSettings( const PAGE_INFO& aPageSettings ); /** * Set the line width for the next drawing. * @param width is specified in IUs */ virtual void SetCurrentLineWidth( int width ) = 0; /** * Set the default line width. Used at the beginning and when a width * of -1 is requested. * @param width is specified in IUs */ virtual void SetDefaultLineWidth( int width ) = 0; virtual int GetCurrentLineWidth() const { return currentPenWidth; } virtual void SetColor( EDA_COLOR_T color ) = 0; virtual void SetDash( bool dashed ) = 0; /** PLEASE NOTE: the plot width adjustment is actually done by the * pcbnew routines, the plotter class only carry it along! * XXX In fact it's only used during postscript plot, I'd move this * variable as a static in pcbnew/plot_rtn.cpp. Also: why it's double? * it's added to pad/track size and it's specified in IU, so it should * be an int */ virtual void SetPlotWidthAdj( double width ) { } virtual double GetPlotWidthAdj() { return 0.; } virtual void SetCreator( const wxString& _creator ) { creator = _creator; } virtual void SetFilename( const wxString& _filename ) { filename = _filename; } /** * Set the plot offset and scaling for the current plot * @param aIusPerDecimil gives the scaling factor from IUs to device * units * @param aScale is the user set plot scaling factor (either explicitly * or using 'fit to A4') * @param aMirror flips the plot in the Y direction (useful for toner * transfers or some kind of film) */ virtual void SetViewport( const wxPoint& aOffset, double aIusPerDecimil, double aScale, bool aMirror ) = 0; // Low level primitives virtual void Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width = -1 ) = 0; virtual void Circle( const wxPoint& pos, int diametre, FILL_T fill, int width = -1 ) = 0; virtual void Arc( const wxPoint& centre, int StAngle, int EndAngle, int rayon, FILL_T fill, int width = -1 ); /** * moveto/lineto primitive, moves the 'pen' to the specified direction * @param plume specifies the kind of motion: 'U' only moves the pen, * 'D' draw a line from the current position and 'Z' finish * the drawing and returns the 'pen' to rest (flushes the trace) */ virtual void PenTo( const wxPoint& pos, char plume ) = 0; // Convenience functions for PenTo void MoveTo( const wxPoint& pos ) { PenTo( pos, 'U' ); } void LineTo( const wxPoint& pos ) { PenTo( pos, 'D' ); } void FinishTo( const wxPoint& pos ) { PenTo( pos, 'D' ); PenTo( pos, 'Z' ); } void PenFinish() { // The point is not important with Z motion PenTo( wxPoint( 0, 0 ), 'Z' ); } /** * Function PlotPoly * @brief Draw a polygon ( filled or not ) * @param aCornerList = corners list * @param aFill = type of fill * @param aWidth = line width */ virtual void PlotPoly( const std::vector< wxPoint >& aCornerList, FILL_T aFill, int aWidth = -1 ) = 0; /** * Function PlotImage * Only Postscript plotters can plot bitmaps * for plotters that cannot plot a bitmap, a rectangle is plotted * @brief Draw an image bitmap * @param aImage = the bitmap * @param aPos = position of the center of the bitmap * @param aScaleFactor = the scale factor to apply to the bitmap size * (this is not the plot scale factor) */ virtual void PlotImage( const wxImage & aImage, const wxPoint& aPos, double aScaleFactor ); // Higher level primitives -- can be drawn as line, sketch or 'filled' virtual void ThickSegment( const wxPoint& start, const wxPoint& end, int width, EDA_DRAW_MODE_T tracemode ); virtual void ThickArc( const wxPoint& centre, int StAngle, int EndAngle, int rayon, int width, EDA_DRAW_MODE_T tracemode ); virtual void ThickRect( const wxPoint& p1, const wxPoint& p2, int width, EDA_DRAW_MODE_T tracemode ); virtual void ThickCircle( const wxPoint& pos, int diametre, int width, EDA_DRAW_MODE_T tracemode ); // Flash primitives virtual void FlashPadCircle( const wxPoint& pos, int diametre, EDA_DRAW_MODE_T trace_mode ) = 0; virtual void FlashPadOval( const wxPoint& pos, const wxSize& size, int orient, EDA_DRAW_MODE_T trace_mode ) = 0; virtual void FlashPadRect( const wxPoint& pos, const wxSize& size, int orient, EDA_DRAW_MODE_T trace_mode ) = 0; /** virtual function FlashPadTrapez * flash a trapezoidal pad * @param aPadPos = the position of the shape * @param aCorners = the list of 4 corners positions, * relative to the shape position, pad orientation 0 * @param aPadOrient = the rotation of the shape * @param aTrace_Mode = FILLED or SKETCH */ virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners, int aPadOrient, EDA_DRAW_MODE_T aTrace_Mode ) = 0; /** * Draws text with the plotter. For convenience it accept the color to use */ virtual void Text( const wxPoint& aPos, enum EDA_COLOR_T aColor, 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 ); /** * Draw a marker (used for the drill map) */ static const unsigned MARKER_COUNT = 58; void Marker( const wxPoint& position, int diametre, unsigned aShapeId ); /** * Function SetLayerPolarity * sets current Gerber layer polarity to positive or negative * by writing \%LPD*\% or \%LPC*\% to the Gerber file, respectively. * (obviously starts a new Gerber layer, too) * @param aPositive is the layer polarity and true for positive. * It's not useful with most other plotter since they can't 'scratch' * the film like photoplotter imagers do */ virtual void SetLayerPolarity( bool aPositive ) { // NOP for most plotters } protected: // These are marker subcomponents void markerCircle( const wxPoint& pos, int radius ); void markerHBar( const wxPoint& pos, int radius ); void markerSlash( const wxPoint& pos, int radius ); void markerBackSlash( const wxPoint& pos, int radius ); void markerVBar( const wxPoint& pos, int radius ); void markerSquare( const wxPoint& position, int radius ); void markerLozenge( const wxPoint& position, int radius ); // Helper function for sketched filler segment void segmentAsOval( const wxPoint& start, const wxPoint& end, int width, EDA_DRAW_MODE_T tracemode ); void sketchOval( const wxPoint& pos, const wxSize& size, int orient, int width ); // Coordinate and scaling conversion functions virtual DPOINT userToDeviceCoordinates( const wxPoint& pos ); virtual DPOINT userToDeviceSize( const wxSize& size ); virtual double userToDeviceSize( double size ); /// Plot scale - chosen by the user (even implicitly with 'fit in a4') double plotScale; /// Device scale (from IUs to device units - usually decimils) double iuPerDeviceUnit; /// Plot offset (in IUs) wxPoint plotOffset; /// Output file FILE* outputFile; // Pen handling bool colorMode, negativeMode; int defaultPenWidth; int currentPenWidth; /// Current pen state: 'U', 'D' or 'Z' (see PenTo) char penState; /// Last pen positions; set to -1,-1 when the pen is at rest wxPoint penLastpos; bool plotMirror; wxString creator; wxString filename; PAGE_INFO pageInfo; /// Paper size in IU - not in mils wxSize paperSize; }; class HPGL_PLOTTER : public PLOTTER { public: HPGL_PLOTTER() { } virtual PlotFormat GetPlotterType() const { return PLOT_FORMAT_HPGL; } virtual bool StartPlot( FILE* fout ); virtual bool EndPlot(); /// HPGL doesn't handle line thickness or color virtual void SetCurrentLineWidth( int width ) { // This is the truth currentPenWidth = userToDeviceSize( penDiameter ); } virtual void SetDefaultLineWidth( int width ) {}; virtual void SetDash( bool dashed ); virtual void SetColor( EDA_COLOR_T color ) {}; virtual void SetPenSpeed( int speed ) { wxASSERT( outputFile == 0 ); penSpeed = speed; } virtual void SetPenNumber( int number ) { wxASSERT( outputFile == 0 ); penNumber = number; } virtual void SetPenDiameter( double diameter ) { wxASSERT( outputFile == 0 ); penDiameter = diameter; } virtual void SetPenOverlap( double overlap ) { wxASSERT( outputFile == 0 ); penOverlap = overlap; } virtual void SetViewport( const wxPoint& aOffset, double aIusPerDecimil, double aScale, bool aMirror ); virtual void Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width = -1 ); virtual void Circle( const wxPoint& pos, int diametre, FILL_T fill, int width = -1 ); virtual void PlotPoly( const std::vector< wxPoint >& aCornerList, FILL_T aFill, int aWidth = -1); virtual void ThickSegment( const wxPoint& start, const wxPoint& end, int width, EDA_DRAW_MODE_T tracemode ); virtual void Arc( const wxPoint& centre, int StAngle, int EndAngle, int rayon, FILL_T fill, int width = -1 ); virtual void PenTo( const wxPoint& pos, char plume ); virtual void FlashPadCircle( const wxPoint& pos, int diametre, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadOval( const wxPoint& pos, const wxSize& size, int orient, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadRect( const wxPoint& pos, const wxSize& size, int orient, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners, int aPadOrient, EDA_DRAW_MODE_T aTrace_Mode ); protected: void penControl( char plume ); int penSpeed; int penNumber; double penDiameter; double penOverlap; }; /** * The PSLIKE_PLOTTER class is an intermediate class to handle common * routines for engines working more or less with the postscript imaging * model */ class PSLIKE_PLOTTER : public PLOTTER { public: PSLIKE_PLOTTER() : plotScaleAdjX( 1 ), plotScaleAdjY( 1 ), plotWidthAdj( 0 ), psTextMode( PSTEXTMODE_PHANTOM ) { } /** * Change the current postscript text mode */ void SetPsTextMode( PostscriptTextMode mode ) { psTextMode = mode; } virtual void SetDefaultLineWidth( int width ); /** * Set the 'fine' scaling for the postscript engine */ void SetScaleAdjust( double scaleX, double scaleY ) { plotScaleAdjX = scaleX; plotScaleAdjY = scaleY; } /** * Set the 'width adjustment' for the postscript engine * (useful for controlling toner bleeding during direct transfer) */ virtual void SetPlotWidthAdj( double width ) { plotWidthAdj = width; } virtual double GetPlotWidthAdj() const { return plotWidthAdj; } // Pad routines are handled with lower level primitives virtual void FlashPadCircle( const wxPoint& pos, int diametre, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadOval( const wxPoint& pos, const wxSize& size, int orient, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadRect( const wxPoint& pos, const wxSize& size, int orient, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners, int aPadOrient, EDA_DRAW_MODE_T aTrace_Mode ); /** The SetColor implementation is split with the subclasses: * The PSLIKE computes the rgb values, the subclass emits the * operator to actually do it */ virtual void SetColor( EDA_COLOR_T color ); protected: void 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 ); void postscriptOverlinePositions( const wxString& aText, int aXSize, bool aItalic, bool aBold, std::vector *pos_pairs ); void fputsPostscriptString(FILE *fout, const wxString& txt); /// Virtual primitive for emitting the setrgbcolor operator virtual void emitSetRGBColor( double r, double g, double b ) = 0; /// Height of the postscript font (from the AFM) static const double postscriptTextAscent = 0.718; int returnPostscriptTextWidth( const wxString& aText, int aXSize, bool aItalic, bool aBold ); /// Fine user scale double plotScaleAdjX, plotScaleAdjY; /** Plot width adjust XXX should be moved in the PCB plotting * routines! */ double plotWidthAdj; /// How to draw text PostscriptTextMode psTextMode; }; class PS_PLOTTER : public PSLIKE_PLOTTER { public: PS_PLOTTER() { } virtual PlotFormat GetPlotterType() const { return PLOT_FORMAT_POST; } virtual bool StartPlot( FILE* fout ); virtual bool EndPlot(); virtual void SetCurrentLineWidth( int width ); virtual void SetDash( bool dashed ); virtual void SetViewport( const wxPoint& aOffset, double aIusPerDecimil, double aScale, bool aMirror ); virtual void Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width = -1 ); virtual void Circle( const wxPoint& pos, int diametre, FILL_T fill, int width = -1 ); virtual void Arc( const wxPoint& centre, int StAngle, int EndAngle, int rayon, FILL_T fill, int width = -1 ); virtual void PlotPoly( const std::vector< wxPoint >& aCornerList, FILL_T aFill, int aWidth = -1); virtual void PlotImage( const wxImage& aImage, const wxPoint& aPos, double aScaleFactor ); virtual void PenTo( const wxPoint& pos, char plume ); virtual void Text( const wxPoint& aPos, enum EDA_COLOR_T aColor, 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 ); protected: virtual void emitSetRGBColor( double r, double g, double b ); }; class PDF_PLOTTER : public PSLIKE_PLOTTER { public: PDF_PLOTTER() : pageStreamHandle( 0 ), workFile( NULL ) { } virtual PlotFormat GetPlotterType() const { return PLOT_FORMAT_PDF; } virtual bool StartPlot( FILE* fout ); virtual bool EndPlot(); virtual void StartPage(); virtual void ClosePage(); virtual void SetCurrentLineWidth( int width ); virtual void SetDash( bool dashed ); /** PDF can have multiple pages, so SetPageSettings can be called * with the outputFile open (but not inside a page stream!) */ virtual void SetPageSettings( const PAGE_INFO& aPageSettings ); virtual void SetViewport( const wxPoint& aOffset, double aIusPerDecimil, double aScale, bool aMirror ); virtual void Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width = -1 ); virtual void Circle( const wxPoint& pos, int diametre, FILL_T fill, int width = -1 ); virtual void Arc( const wxPoint& centre, int StAngle, int EndAngle, int rayon, FILL_T fill, int width = -1 ); virtual void PlotPoly( const std::vector< wxPoint >& aCornerList, FILL_T aFill, int aWidth = -1); virtual void PenTo( const wxPoint& pos, char plume ); virtual void Text( const wxPoint& aPos, enum EDA_COLOR_T aColor, 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 ); virtual void PlotImage( const wxImage& aImage, const wxPoint& aPos, double aScaleFactor ); protected: virtual void emitSetRGBColor( double r, double g, double b ); int allocPdfObject(); int startPdfObject(int handle = -1); void closePdfObject(); int startPdfStream(int handle = -1); void closePdfStream(); int pageTreeHandle; /// Handle to the root of the page tree object int fontResDictHandle; /// Font resource dictionary std::vector pageHandles;/// Handles to the page objects int pageStreamHandle; /// Handle of the page content object int streamLengthHandle; /// Handle to the deferred stream length wxString workFilename; FILE* workFile; /// Temporary file to costruct the stream before zipping std::vector xrefTable; /// The PDF xref offset table }; /* Class to handle a D_CODE when plotting a board : */ #define FIRST_DCODE_VALUE 10 // D_CODE < 10 is a command, D_CODE >= 10 is a tool struct APERTURE { enum APERTURE_TYPE { Circle = 1, Rect = 2, Plotting = 3, Oval = 4 }; wxSize Size; // horiz and Vert size APERTURE_TYPE Type; // Type ( Line, rect , circulaire , ovale .. ) int DCode; // code number ( >= 10 ); /* Trivia question: WHY Gerber decided to use D instead of the usual T for * tool change? */ }; class GERBER_PLOTTER : public PLOTTER { public: GERBER_PLOTTER() { workFile = 0; finalFile = 0; currentAperture = apertures.end(); } virtual PlotFormat GetPlotterType() const { return PLOT_FORMAT_GERBER; } virtual bool StartPlot( FILE* fout ); virtual bool EndPlot(); virtual void SetCurrentLineWidth( int width ); virtual void SetDefaultLineWidth( int width ); // RS274X has no dashing, nor colours virtual void SetDash( bool dashed ) {}; virtual void SetColor( EDA_COLOR_T color ) {}; virtual void SetViewport( const wxPoint& aOffset, double aIusPerDecimil, double aScale, bool aMirror ); virtual void Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width = -1 ); virtual void Circle( const wxPoint& pos, int diametre, FILL_T fill, int width = -1 ); virtual void PlotPoly( const std::vector< wxPoint >& aCornerList, FILL_T aFill, int aWidth = -1); virtual void PenTo( const wxPoint& pos, char plume ); virtual void FlashPadCircle( const wxPoint& pos, int diametre, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadOval( const wxPoint& pos, const wxSize& size, int orient, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadRect( const wxPoint& pos, const wxSize& size, int orient, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners, int aPadOrient, EDA_DRAW_MODE_T aTrace_Mode ); virtual void SetLayerPolarity( bool aPositive ); protected: void selectAperture( const wxSize& size, APERTURE::APERTURE_TYPE type ); void emitDcode( const DPOINT& pt, int dcode ); std::vector::iterator getAperture( const wxSize& size, APERTURE::APERTURE_TYPE type ); FILE* workFile; FILE* finalFile; wxString m_workFilename; void writeApertureList(); std::vector apertures; std::vector::iterator currentAperture; }; class DXF_PLOTTER : public PLOTTER { public: DXF_PLOTTER() : textAsLines( false ) { } virtual PlotFormat GetPlotterType() const { return PLOT_FORMAT_DXF; } /// We can plot text as strokes or as TEXT entities void SetDXFTextMode( bool aTextAsLines ) { textAsLines = aTextAsLines; } virtual bool StartPlot( FILE* fout ); virtual bool EndPlot(); // For now we don't use 'thick' primitives, so no line width virtual void SetCurrentLineWidth( int width ) { currentPenWidth = 0; } virtual void SetDefaultLineWidth( int width ) { // DXF lines are infinitesimal defaultPenWidth = 0; } virtual void SetDash( bool dashed ); virtual void SetColor( EDA_COLOR_T color ); virtual void SetViewport( const wxPoint& aOffset, double aIusPerDecimil, double aScale, bool aMirror ); virtual void Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width = -1 ); virtual void Circle( const wxPoint& pos, int diametre, FILL_T fill, int width = -1 ); virtual void PlotPoly( const std::vector< wxPoint >& aCornerList, FILL_T aFill, int aWidth = -1 ); virtual void ThickSegment( const wxPoint& start, const wxPoint& end, int width, EDA_DRAW_MODE_T tracemode ); virtual void Arc( const wxPoint& centre, int StAngle, int EndAngle, int rayon, FILL_T fill, int width = -1 ); virtual void PenTo( const wxPoint& pos, char plume ); virtual void FlashPadCircle( const wxPoint& pos, int diametre, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadOval( const wxPoint& pos, const wxSize& size, int orient, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadRect( const wxPoint& pos, const wxSize& size, int orient, EDA_DRAW_MODE_T trace_mode ); virtual void FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners, int aPadOrient, EDA_DRAW_MODE_T aTrace_Mode ); virtual void Text( const wxPoint& aPos, enum EDA_COLOR_T aColor, 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 ); protected: bool textAsLines; int currentColor; }; #endif // PLOT_COMMON_H_