HPGL driver: collect graphics to plot later
This will later enable sorting the items for efficiency, which will then facilitate things that would otherwise be impossibly slow (e.g. switching pens)
This commit is contained in:
parent
4bc12e7dcd
commit
54d2748032
|
@ -215,6 +215,8 @@ static const char hpgl_end_polygon_cmd[] = "PM 2; FP; EP;\n";
|
|||
static const double PLUsPERDECIMIL = 0.1016;
|
||||
|
||||
HPGL_PLOTTER::HPGL_PLOTTER()
|
||||
: dashType( PLOT_DASH_TYPE::SOLID ),
|
||||
m_current_item( nullptr )
|
||||
{
|
||||
SetPenSpeed( 40 ); // Default pen speed = 40 cm/s; Pen speed is *always* in cm
|
||||
SetPenNumber( 1 ); // Default pen num = 1
|
||||
|
@ -258,6 +260,74 @@ bool HPGL_PLOTTER::StartPlot()
|
|||
bool HPGL_PLOTTER::EndPlot()
|
||||
{
|
||||
wxASSERT( m_outputFile );
|
||||
fputs( "PU;", m_outputFile );
|
||||
|
||||
flushItem();
|
||||
if( m_items.size() > 0 ) {
|
||||
|
||||
DPOINT loc = m_items.begin()->loc_start;
|
||||
bool pen_up = true;
|
||||
PLOT_DASH_TYPE current_dash = PLOT_DASH_TYPE::SOLID;
|
||||
int current_pen = penNumber;
|
||||
|
||||
for( HPGL_ITEM const & item: m_items ) {
|
||||
if( item.loc_start != loc || pen_up ) {
|
||||
if( !pen_up ) {
|
||||
fputs( "PU;", m_outputFile );
|
||||
pen_up = true;
|
||||
}
|
||||
|
||||
fprintf(
|
||||
m_outputFile,
|
||||
"PA %.0f,%.0f;",
|
||||
item.loc_start.x, item.loc_start.y
|
||||
);
|
||||
}
|
||||
|
||||
if( item.dashType != current_dash ) {
|
||||
current_dash = item.dashType;
|
||||
switch( item.dashType ) {
|
||||
case PLOT_DASH_TYPE::DASH:
|
||||
fputs( "LT -2 4 1;", m_outputFile );
|
||||
break;
|
||||
case PLOT_DASH_TYPE::DOT:
|
||||
fputs( "LT -1 2 1;", m_outputFile );
|
||||
break;
|
||||
case PLOT_DASH_TYPE::DASHDOT:
|
||||
fputs( "LT -4 6 1;", m_outputFile );
|
||||
break;
|
||||
default:
|
||||
fputs( "LT;", m_outputFile );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( item.pen != current_pen ) {
|
||||
if( !pen_up ) {
|
||||
fputs( "PU;", m_outputFile );
|
||||
pen_up = true;
|
||||
}
|
||||
fprintf( m_outputFile, "SP%d;", item.pen );
|
||||
current_pen = item.pen;
|
||||
}
|
||||
|
||||
if( pen_up ) {
|
||||
fputs( "PD;", m_outputFile );
|
||||
pen_up = false;
|
||||
}
|
||||
|
||||
fputs( item.content, m_outputFile );
|
||||
|
||||
if( item.lift_after ) {
|
||||
fputs( "PU;", m_outputFile );
|
||||
pen_up = true;
|
||||
} else {
|
||||
loc = item.loc_end;
|
||||
}
|
||||
fputs( "\n", m_outputFile );
|
||||
}
|
||||
}
|
||||
|
||||
fputs( "PU;PA;SP0;\n", m_outputFile );
|
||||
fclose( m_outputFile );
|
||||
m_outputFile = NULL;
|
||||
|
@ -276,9 +346,20 @@ void HPGL_PLOTTER::SetPenDiameter( double diameter )
|
|||
void HPGL_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_TYPE fill, int width )
|
||||
{
|
||||
wxASSERT( m_outputFile );
|
||||
DPOINT p1dev = userToDeviceCoordinates( p1 );
|
||||
DPOINT p2dev = userToDeviceCoordinates( p2 );
|
||||
|
||||
MoveTo( p1 );
|
||||
fprintf( m_outputFile, "EA %.0f,%.0f;\n", p2dev.x, p2dev.y );
|
||||
startOrAppendItem( p1dev,
|
||||
wxString::Format(
|
||||
"EA %.0f,%.0f;", p2dev.x, p2dev.y
|
||||
)
|
||||
);
|
||||
|
||||
// Don't know where the pen is, so lift it
|
||||
// TODO this might actually be documented, this could be optimized to
|
||||
// m_current->item->loc_end = ?
|
||||
m_current_item->lift_after = true;
|
||||
PenFinish();
|
||||
}
|
||||
|
||||
|
@ -289,21 +370,33 @@ void HPGL_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_TYPE fill,
|
|||
{
|
||||
wxASSERT( m_outputFile );
|
||||
double radius = userToDeviceSize( diameter / 2 );
|
||||
DPOINT center_dev = userToDeviceCoordinates( centre );
|
||||
SetCurrentLineWidth( width );
|
||||
|
||||
if( fill == FILL_TYPE::FILLED_SHAPE )
|
||||
{
|
||||
// Draw the filled area
|
||||
MoveTo( centre );
|
||||
fprintf( m_outputFile, "PM 0; CI %g;\n", radius );
|
||||
fprintf( m_outputFile, hpgl_end_polygon_cmd ); // Close, fill polygon and draw outlines
|
||||
startOrAppendItem(
|
||||
center_dev,
|
||||
wxString::Format(
|
||||
"PM 0;CI %g;%s", radius, hpgl_end_polygon_cmd
|
||||
)
|
||||
);
|
||||
m_current_item->lift_after = true;
|
||||
PenFinish();
|
||||
}
|
||||
|
||||
if( radius > 0 )
|
||||
{
|
||||
MoveTo( centre );
|
||||
fprintf( m_outputFile, "CI %g;\n", radius );
|
||||
startOrAppendItem(
|
||||
center_dev,
|
||||
wxString::Format(
|
||||
"CI %g;", radius
|
||||
)
|
||||
);
|
||||
m_current_item->lift_after = true;
|
||||
PenFinish();
|
||||
}
|
||||
}
|
||||
|
@ -328,12 +421,14 @@ void HPGL_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList,
|
|||
}
|
||||
|
||||
MoveTo( aCornerList[0] );
|
||||
startItem( userToDeviceCoordinates( aCornerList[0] ) );
|
||||
|
||||
if( aFill == FILL_TYPE::FILLED_SHAPE )
|
||||
{
|
||||
// Draw the filled area
|
||||
SetCurrentLineWidth( USE_DEFAULT_LINE_WIDTH );
|
||||
fprintf( m_outputFile, "PM 0;\n" ); // Start polygon
|
||||
|
||||
m_current_item->content << wxString( "PM 0;\n" ); // Start polygon
|
||||
|
||||
for( unsigned ii = 1; ii < aCornerList.size(); ++ii )
|
||||
LineTo( aCornerList[ii] );
|
||||
|
@ -343,7 +438,8 @@ void HPGL_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList,
|
|||
if( aCornerList[ii] != aCornerList[0] )
|
||||
LineTo( aCornerList[0] );
|
||||
|
||||
fprintf( m_outputFile, hpgl_end_polygon_cmd ); // Close, fill polygon and draw outlines
|
||||
m_current_item->content << hpgl_end_polygon_cmd; // Close, fill polygon and draw outlines
|
||||
m_current_item->lift_after = true;
|
||||
}
|
||||
else if( aWidth > 0 )
|
||||
{
|
||||
|
@ -370,6 +466,8 @@ void HPGL_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList,
|
|||
*/
|
||||
void HPGL_PLOTTER::penControl( char plume )
|
||||
{
|
||||
m_penState = plume;
|
||||
/*
|
||||
wxASSERT( m_outputFile );
|
||||
|
||||
switch( plume )
|
||||
|
@ -401,6 +499,7 @@ void HPGL_PLOTTER::penControl( char plume )
|
|||
m_penLastpos.y = -1;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
@ -411,14 +510,32 @@ void HPGL_PLOTTER::PenTo( const wxPoint& pos, char plume )
|
|||
if( plume == 'Z' )
|
||||
{
|
||||
penControl( 'Z' );
|
||||
flushItem();
|
||||
return;
|
||||
}
|
||||
|
||||
penControl( plume );
|
||||
DPOINT pos_dev = userToDeviceCoordinates( pos );
|
||||
DPOINT lastpos_dev = userToDeviceCoordinates( m_penLastpos );
|
||||
|
||||
if( m_penLastpos != pos )
|
||||
fprintf( m_outputFile, "PA %.0f,%.0f;\n", pos_dev.x, pos_dev.y );
|
||||
if( plume == 'U' )
|
||||
{
|
||||
penControl( 'U' );
|
||||
flushItem();
|
||||
}
|
||||
else if( plume == 'D' )
|
||||
{
|
||||
penControl( 'D' );
|
||||
startOrAppendItem(
|
||||
lastpos_dev,
|
||||
wxString::Format(
|
||||
"PA %.0f,%.0f;",
|
||||
pos_dev.x,
|
||||
pos_dev.y
|
||||
)
|
||||
);
|
||||
m_current_item->loc_end = pos_dev;
|
||||
}
|
||||
|
||||
m_penLastpos = pos;
|
||||
}
|
||||
|
@ -429,6 +546,8 @@ void HPGL_PLOTTER::PenTo( const wxPoint& pos, char plume )
|
|||
*/
|
||||
void HPGL_PLOTTER::SetDash( PLOT_DASH_TYPE dashed )
|
||||
{
|
||||
dashType = dashed;
|
||||
/*
|
||||
wxASSERT( m_outputFile );
|
||||
|
||||
switch( dashed )
|
||||
|
@ -445,6 +564,7 @@ void HPGL_PLOTTER::SetDash( PLOT_DASH_TYPE dashed )
|
|||
default:
|
||||
fputs( "LT;\n", m_outputFile );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
@ -499,13 +619,17 @@ void HPGL_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle,
|
|||
cmap.y = centre.y - KiROUND( sindecideg( radius, StAngle ) );
|
||||
DPOINT cmap_dev = userToDeviceCoordinates( cmap );
|
||||
|
||||
fprintf( m_outputFile,
|
||||
"PU;PA %.0f,%.0f;PD;AA %.0f,%.0f,",
|
||||
cmap_dev.x, cmap_dev.y,
|
||||
centre_dev.x, centre_dev.y );
|
||||
fprintf( m_outputFile, "%.0f", angle );
|
||||
fprintf( m_outputFile, ";PU;\n" );
|
||||
PenFinish();
|
||||
startOrAppendItem(
|
||||
cmap_dev,
|
||||
wxString::Format(
|
||||
"AA %.0f,%.0f",
|
||||
centre_dev.x, centre_dev.y
|
||||
)
|
||||
);
|
||||
|
||||
// TODO We could compute the final position instead...
|
||||
m_current_item->lift_after = true;
|
||||
flushItem();
|
||||
}
|
||||
|
||||
|
||||
|
@ -575,14 +699,21 @@ void HPGL_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre,
|
|||
// Gives a correct current starting point for the circle
|
||||
MoveTo( wxPoint( pos.x+radius, pos.y ) );
|
||||
// Plot filled area and its outline
|
||||
fprintf( m_outputFile, "PM 0; PA %.0f,%.0f;CI %.0f;%s",
|
||||
pos_dev.x, pos_dev.y, rsize, hpgl_end_polygon_cmd );
|
||||
startOrAppendItem(
|
||||
userToDeviceCoordinates( wxPoint( pos.x+radius, pos.y ) ),
|
||||
wxString::Format(
|
||||
"PM 0; PA %.0f,%.0f;CI %.0f;%s",
|
||||
pos_dev.x, pos_dev.y, rsize, hpgl_end_polygon_cmd
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw outline only:
|
||||
fprintf( m_outputFile, "PA %.0f,%.0f;CI %.0f;\n",
|
||||
pos_dev.x, pos_dev.y, rsize );
|
||||
startOrAppendItem(
|
||||
pos_dev,
|
||||
wxString::Format( "CI %.0f;", rsize )
|
||||
);
|
||||
}
|
||||
|
||||
PenFinish();
|
||||
|
@ -716,3 +847,36 @@ void HPGL_PLOTTER::FlashRegularPolygon( const wxPoint& aShapePos,
|
|||
// Do nothing
|
||||
wxASSERT( 0 );
|
||||
}
|
||||
|
||||
|
||||
bool HPGL_PLOTTER::startItem( DPOINT location )
|
||||
{
|
||||
return startOrAppendItem( location, wxEmptyString );
|
||||
}
|
||||
|
||||
|
||||
void HPGL_PLOTTER::flushItem( )
|
||||
{
|
||||
m_current_item = nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool HPGL_PLOTTER::startOrAppendItem( DPOINT location, wxString const & content )
|
||||
{
|
||||
if( m_current_item == nullptr ) {
|
||||
HPGL_ITEM item = {
|
||||
location,
|
||||
location,
|
||||
false,
|
||||
penNumber,
|
||||
dashType,
|
||||
content
|
||||
};
|
||||
m_items.push_back( item );
|
||||
m_current_item = &m_items.back();
|
||||
return true;
|
||||
} else {
|
||||
m_current_item->content << content;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <math/box2.h>
|
||||
#include <eda_item.h> // FILL_TYPE
|
||||
#include <plotter.h>
|
||||
|
@ -108,9 +109,42 @@ public:
|
|||
protected:
|
||||
void penControl( char plume );
|
||||
|
||||
/// Start a new HPGL_ITEM if necessary, keeping the current one if it exists.
|
||||
///
|
||||
/// @param location - location of the item
|
||||
///
|
||||
/// @return whether a new item was made
|
||||
bool startItem( DPOINT location );
|
||||
|
||||
/// Flush the current HPGL_ITEM and clear out the current item pointer.
|
||||
void flushItem( );
|
||||
|
||||
/// Start a new HPGL_ITEM with the given string if necessary, or append the
|
||||
/// string to the current item.
|
||||
///
|
||||
/// @param location - location of the item, if a new one is made
|
||||
/// @param content - content substring
|
||||
///
|
||||
/// @return whether a new item was made
|
||||
bool startOrAppendItem( DPOINT location, wxString const & content );
|
||||
|
||||
int penSpeed;
|
||||
int penNumber;
|
||||
double penDiameter;
|
||||
PLOT_DASH_TYPE dashType;
|
||||
|
||||
struct HPGL_ITEM
|
||||
{
|
||||
DPOINT loc_start;
|
||||
DPOINT loc_end;
|
||||
bool lift_after;
|
||||
int pen;
|
||||
PLOT_DASH_TYPE dashType;
|
||||
wxString content;
|
||||
};
|
||||
|
||||
std::list<HPGL_ITEM> m_items;
|
||||
HPGL_ITEM * m_current_item;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue