Add user coordinate support to HPGL plotter

This commit is contained in:
Alexis Lockwood 2020-12-21 16:27:31 -07:00 committed by Alexis V L
parent 5676117d0b
commit f5b7595675
9 changed files with 143 additions and 26 deletions

View File

@ -223,6 +223,8 @@ HPGL_PLOTTER::HPGL_PLOTTER()
: arcTargetChordLength( 0 ), : arcTargetChordLength( 0 ),
arcMinChordDegrees( 5.0 ), arcMinChordDegrees( 5.0 ),
dashType( PLOT_DASH_TYPE::SOLID ), dashType( PLOT_DASH_TYPE::SOLID ),
useUserCoords( false ),
fitUserCoords( false ),
m_current_item( nullptr ) m_current_item( nullptr )
{ {
SetPenSpeed( 40 ); // Default pen speed = 40 cm/s; Pen speed is *always* in cm SetPenSpeed( 40 ); // Default pen speed = 40 cm/s; Pen speed is *always* in cm
@ -273,13 +275,34 @@ bool HPGL_PLOTTER::StartPlot()
bool HPGL_PLOTTER::EndPlot() bool HPGL_PLOTTER::EndPlot()
{ {
wxASSERT( m_outputFile ); wxASSERT( m_outputFile );
fputs( "PU;", m_outputFile );
fputs( "PU;\n", m_outputFile );
flushItem(); flushItem();
sortItems( m_items ); sortItems( m_items );
if( m_items.size() > 0 ) if( m_items.size() > 0 )
{ {
if( useUserCoords )
{
if( fitUserCoords )
{
BOX2D bbox = m_items.front().bbox;
for( HPGL_ITEM const& item: m_items )
{
bbox.Merge( item.bbox );
}
fprintf( m_outputFile, "SC%.0f,%.0f,%.0f,%.0f;\n", bbox.GetX(), bbox.GetX() + bbox.GetWidth(),
bbox.GetY(), bbox.GetY() + bbox.GetHeight() );
}
else
{
DPOINT pagesize_dev( m_paperSize * m_iuPerDeviceUnit );
fprintf( m_outputFile, "SC%.0f,%.0f,%.0f,%.0f;\n", 0., pagesize_dev.x, 0., pagesize_dev.y );
}
}
DPOINT loc = m_items.begin()->loc_start; DPOINT loc = m_items.begin()->loc_start;
bool pen_up = true; bool pen_up = true;
PLOT_DASH_TYPE current_dash = PLOT_DASH_TYPE::SOLID; PLOT_DASH_TYPE current_dash = PLOT_DASH_TYPE::SOLID;
@ -376,6 +399,7 @@ void HPGL_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_TYPE fill, i
startOrAppendItem( p1dev, wxString::Format( "EA %.0f,%.0f;", p2dev.x, p2dev.y ) ); startOrAppendItem( p1dev, wxString::Format( "EA %.0f,%.0f;", p2dev.x, p2dev.y ) );
m_current_item->loc_end = m_current_item->loc_start; m_current_item->loc_end = m_current_item->loc_start;
m_current_item->bbox.Merge( p2dev );
PenFinish(); PenFinish();
} }
@ -410,6 +434,9 @@ void HPGL_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_TYPE fill,
hpgl_end_polygon_cmd ) ); hpgl_end_polygon_cmd ) );
m_current_item->lift_before = true; m_current_item->lift_before = true;
m_current_item->pen_returns = true; m_current_item->pen_returns = true;
m_current_item->bbox.Merge(
BOX2D( center_dev - radius, VECTOR2D( 2 * radius, 2 * radius ) )
);
PenFinish(); PenFinish();
} }
@ -419,6 +446,9 @@ void HPGL_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_TYPE fill,
startOrAppendItem( center_dev, wxString::Format( "CI %g,%g;", radius, chord_degrees ) ); startOrAppendItem( center_dev, wxString::Format( "CI %g,%g;", radius, chord_degrees ) );
m_current_item->lift_before = true; m_current_item->lift_before = true;
m_current_item->pen_returns = true; m_current_item->pen_returns = true;
m_current_item->bbox.Merge(
BOX2D( center_dev - radius, VECTOR2D( 2 * radius, 2 * radius ) )
);
PenFinish(); PenFinish();
} }
} }
@ -514,6 +544,7 @@ void HPGL_PLOTTER::PenTo( const wxPoint& pos, char plume )
) )
); );
m_current_item->loc_end = pos_dev; m_current_item->loc_end = pos_dev;
m_current_item->bbox.Merge( pos_dev );
} }
m_penLastpos = pos; m_penLastpos = pos;
@ -565,9 +596,10 @@ void HPGL_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle,
if( radius <= 0 ) if( radius <= 0 )
return; return;
double const circumf = 2.0 * M_PI * userToDeviceSize( radius ); double const radius_dev = userToDeviceSize( radius );
double const circumf_dev = 2.0 * M_PI * radius_dev;
double const target_chord_length = arcTargetChordLength; double const target_chord_length = arcTargetChordLength;
double chord_degrees = 360.0 * target_chord_length / circumf; double chord_degrees = 360.0 * target_chord_length / circumf_dev;
if( chord_degrees < arcMinChordDegrees ) if( chord_degrees < arcMinChordDegrees )
{ {
@ -597,7 +629,10 @@ void HPGL_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle,
startOrAppendItem( cmap_dev, wxString::Format( "AA %.0f,%.0f,%.0f,%g", centre_dev.x, startOrAppendItem( cmap_dev, wxString::Format( "AA %.0f,%.0f,%.0f,%g", centre_dev.x,
centre_dev.y, angle, chord_degrees ) ); centre_dev.y, angle, chord_degrees ) );
// TODO We could compute the final position instead... // TODO We could compute the final position and full bounding box instead...
m_current_item->bbox.Merge( BOX2D(
centre_dev - radius_dev, VECTOR2D( radius_dev * 2, radius_dev * 2 )
) );
m_current_item->lift_after = true; m_current_item->lift_after = true;
flushItem(); flushItem();
} }
@ -832,7 +867,13 @@ bool HPGL_PLOTTER::startOrAppendItem( DPOINT location, wxString const& content )
{ {
if( m_current_item == nullptr ) if( m_current_item == nullptr )
{ {
HPGL_ITEM item = { location, location, false, false, false, penNumber, dashType, content }; HPGL_ITEM item;
item.loc_start = location;
item.loc_end = location;
item.bbox = BOX2D( location );
item.pen = penNumber;
item.dashType = dashType;
item.content = content;
m_items.push_back( item ); m_items.push_back( item );
m_current_item = &m_items.back(); m_current_item = &m_items.back();
return true; return true;

View File

@ -54,6 +54,18 @@ public:
/// @param chord_len - chord length in IUs /// @param chord_len - chord length in IUs
void SetTargetChordLength( double chord_len ); void SetTargetChordLength( double chord_len );
/// Switch to the user coordinate system
void SetUserCoords( bool user_coords )
{
useUserCoords = user_coords;
}
/// Set whether the user coordinate system is fit to content
void SetUserCoordsFit( bool user_coords_fit )
{
fitUserCoords = user_coords_fit;
}
virtual bool StartPlot() override; virtual bool StartPlot() override;
virtual bool EndPlot() override; virtual bool EndPlot() override;
@ -133,15 +145,24 @@ protected:
/// @return whether a new item was made /// @return whether a new item was made
bool startOrAppendItem( DPOINT location, wxString const& content ); bool startOrAppendItem( DPOINT location, wxString const& content );
int penSpeed; int penSpeed;
int penNumber; int penNumber;
double penDiameter; double penDiameter;
double arcTargetChordLength; double arcTargetChordLength;
double arcMinChordDegrees; double arcMinChordDegrees;
PLOT_DASH_TYPE dashType; PLOT_DASH_TYPE dashType;
bool useUserCoords;
bool fitUserCoords;
struct HPGL_ITEM struct HPGL_ITEM
{ {
HPGL_ITEM()
: lift_before( false ),
lift_after( false ),
pen_returns( false ),
pen( 0 )
{}
/// Location the pen should start at /// Location the pen should start at
DPOINT loc_start; DPOINT loc_start;
@ -149,6 +170,9 @@ protected:
/// leave it equal to loc_start and set lift_after. /// leave it equal to loc_start and set lift_after.
DPOINT loc_end; DPOINT loc_end;
/// Bounding box of this item
BOX2D bbox;
/// Whether the command should be executed with the pen lifted /// Whether the command should be executed with the pen lifted
bool lift_before; bool lift_before;

View File

@ -96,8 +96,8 @@ void DIALOG_PLOT_SCHEMATIC::initDlg()
// Set plot or not frame reference option // Set plot or not frame reference option
setPlotFrameRef( cfg->m_PlotPanel.frame_reference ); setPlotFrameRef( cfg->m_PlotPanel.frame_reference );
// Set HPGL plot origin to center of paper of left bottom corner // HPGL plot origin and unit system configuration
SetPlotOriginCenter( cfg->m_PlotPanel.hpgl_origin ); m_plotOriginOpt->SetSelection( cfg->m_PlotPanel.hpgl_origin );
m_HPGLPaperSizeSelect = cfg->m_PlotPanel.hpgl_paper_size; m_HPGLPaperSizeSelect = cfg->m_PlotPanel.hpgl_paper_size;
@ -279,7 +279,7 @@ void DIALOG_PLOT_SCHEMATIC::getPlotOptions( RENDER_SETTINGS* aSettings )
cfg->m_PlotPanel.color_theme = colors->GetFilename(); cfg->m_PlotPanel.color_theme = colors->GetFilename();
cfg->m_PlotPanel.frame_reference = getPlotFrameRef(); cfg->m_PlotPanel.frame_reference = getPlotFrameRef();
cfg->m_PlotPanel.format = static_cast<int>( GetPlotFileFormat() ); cfg->m_PlotPanel.format = static_cast<int>( GetPlotFileFormat() );
cfg->m_PlotPanel.hpgl_origin = GetPlotOriginCenter(); cfg->m_PlotPanel.hpgl_origin = m_plotOriginOpt->GetSelection();
cfg->m_PlotPanel.hpgl_paper_size = m_HPGLPaperSizeSelect; cfg->m_PlotPanel.hpgl_paper_size = m_HPGLPaperSizeSelect;
// HPGL Pen Size is stored in mm in config // HPGL Pen Size is stored in mm in config

View File

@ -40,6 +40,13 @@ enum PageFormatReq {
PAGE_SIZE_A PAGE_SIZE_A
}; };
enum class HPGL_PLOT_ORIGIN_AND_UNITS {
PLOTTER_BOT_LEFT,
PLOTTER_CENTER,
USER_FIT_PAGE,
USER_FIT_CONTENT,
};
class PDF_PLOTTER; class PDF_PLOTTER;
class DIALOG_PLOT_SCHEMATIC : public DIALOG_PLOT_SCHEMATIC_BASE class DIALOG_PLOT_SCHEMATIC : public DIALOG_PLOT_SCHEMATIC_BASE
@ -112,21 +119,48 @@ private:
wxPoint aPlot0ffset, double aScale, bool aPlotFrameRef ); wxPoint aPlot0ffset, double aScale, bool aPlotFrameRef );
// HPGL // HPGL
bool GetPlotOriginCenter() HPGL_PLOT_ORIGIN_AND_UNITS GetPlotOriginAndUnits()
{ {
return m_plotOriginOpt->GetSelection() == 1; switch( m_plotOriginOpt->GetSelection() )
{
case 0:
default:
return HPGL_PLOT_ORIGIN_AND_UNITS::PLOTTER_BOT_LEFT;
case 1:
return HPGL_PLOT_ORIGIN_AND_UNITS::PLOTTER_CENTER;
case 2:
return HPGL_PLOT_ORIGIN_AND_UNITS::USER_FIT_PAGE;
case 3:
return HPGL_PLOT_ORIGIN_AND_UNITS::USER_FIT_CONTENT;
}
} }
void SetPlotOriginCenter( bool aCenter ) void SetPlotOriginAndUnits( HPGL_PLOT_ORIGIN_AND_UNITS aOriginAndUnits )
{ {
m_plotOriginOpt->SetSelection( aCenter ? 1 : 0 ); switch( aOriginAndUnits )
{
case HPGL_PLOT_ORIGIN_AND_UNITS::PLOTTER_BOT_LEFT:
default:
m_plotOriginOpt->SetSelection( 0 );
break;
case HPGL_PLOT_ORIGIN_AND_UNITS::PLOTTER_CENTER:
m_plotOriginOpt->SetSelection( 1 );
break;
case HPGL_PLOT_ORIGIN_AND_UNITS::USER_FIT_PAGE:
m_plotOriginOpt->SetSelection( 2 );
break;
case HPGL_PLOT_ORIGIN_AND_UNITS::USER_FIT_CONTENT:
m_plotOriginOpt->SetSelection( 3 );
break;
}
} }
void createHPGLFile( bool aPlotAll, bool aPlotFrameRef, RENDER_SETTINGS* aRenderSettings ); void createHPGLFile( bool aPlotAll, bool aPlotFrameRef, RENDER_SETTINGS* aRenderSettings );
void SetHPGLPenWidth(); void SetHPGLPenWidth();
bool Plot_1_Page_HPGL( const wxString& aFileName, SCH_SCREEN* aScreen, bool Plot_1_Page_HPGL( const wxString& aFileName, SCH_SCREEN* aScreen,
const PAGE_INFO& aPageInfo, RENDER_SETTINGS* aRenderSettings, const PAGE_INFO& aPageInfo, RENDER_SETTINGS* aRenderSettings,
wxPoint aPlot0ffset, double aScale, bool aPlotFrameRef ); wxPoint aPlot0ffset, double aScale, bool aPlotFrameRef,
HPGL_PLOT_ORIGIN_AND_UNITS aOriginAndUnits );
// PS // PS
void createPSFile( bool aPlotAll, bool aPlotFrameRef, RENDER_SETTINGS* aSettings ); void createPSFile( bool aPlotAll, bool aPlotFrameRef, RENDER_SETTINGS* aSettings );

View File

@ -123,11 +123,11 @@ DIALOG_PLOT_SCHEMATIC_BASE::DIALOG_PLOT_SCHEMATIC_BASE( wxWindow* parent, wxWind
gbSizer2->SetFlexibleDirection( wxBOTH ); gbSizer2->SetFlexibleDirection( wxBOTH );
gbSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); gbSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_plotOriginTitle = new wxStaticText( m_HPGLOptionsSizer->GetStaticBox(), wxID_ANY, _("Position:"), wxDefaultPosition, wxDefaultSize, 0 ); m_plotOriginTitle = new wxStaticText( m_HPGLOptionsSizer->GetStaticBox(), wxID_ANY, _("Position and units:"), wxDefaultPosition, wxDefaultSize, 0 );
m_plotOriginTitle->Wrap( -1 ); m_plotOriginTitle->Wrap( -1 );
gbSizer2->Add( m_plotOriginTitle, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 ); gbSizer2->Add( m_plotOriginTitle, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 );
wxString m_plotOriginOptChoices[] = { _("Bottom left"), _("Center on page") }; wxString m_plotOriginOptChoices[] = { _("Bottom left, plotter units"), _("Centered, plotter units"), _("Page fit, user units"), _("Content fit, user units") };
int m_plotOriginOptNChoices = sizeof( m_plotOriginOptChoices ) / sizeof( wxString ); int m_plotOriginOptNChoices = sizeof( m_plotOriginOptChoices ) / sizeof( wxString );
m_plotOriginOpt = new wxChoice( m_HPGLOptionsSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_plotOriginOptNChoices, m_plotOriginOptChoices, 0 ); m_plotOriginOpt = new wxChoice( m_HPGLOptionsSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_plotOriginOptNChoices, m_plotOriginOptChoices, 0 );
m_plotOriginOpt->SetSelection( 0 ); m_plotOriginOpt->SetSelection( 0 );

View File

@ -1164,7 +1164,7 @@
<property name="gripper">0</property> <property name="gripper">0</property>
<property name="hidden">0</property> <property name="hidden">0</property>
<property name="id">wxID_ANY</property> <property name="id">wxID_ANY</property>
<property name="label">Position:</property> <property name="label">Position and units:</property>
<property name="markup">0</property> <property name="markup">0</property>
<property name="max_size"></property> <property name="max_size"></property>
<property name="maximize_button">0</property> <property name="maximize_button">0</property>
@ -1214,7 +1214,7 @@
<property name="caption"></property> <property name="caption"></property>
<property name="caption_visible">1</property> <property name="caption_visible">1</property>
<property name="center_pane">0</property> <property name="center_pane">0</property>
<property name="choices">&quot;Bottom left&quot; &quot;Center on page&quot;</property> <property name="choices">&quot;Bottom left, plotter units&quot; &quot;Centered, plotter units&quot; &quot;Page fit, user units&quot; &quot;Content fit, user units&quot;</property>
<property name="close_button">1</property> <property name="close_button">1</property>
<property name="context_help"></property> <property name="context_help"></property>
<property name="context_menu">1</property> <property name="context_menu">1</property>

View File

@ -258,8 +258,8 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
m_params.emplace_back( new PARAM<double>( "plot.hpgl_pen_size", m_params.emplace_back( new PARAM<double>( "plot.hpgl_pen_size",
&m_PlotPanel.hpgl_pen_size, 0.5 ) ); &m_PlotPanel.hpgl_pen_size, 0.5 ) );
m_params.emplace_back( new PARAM<bool>( "plot.hpgl_origin", m_params.emplace_back( new PARAM<int>( "plot.hpgl_origin",
&m_PlotPanel.hpgl_origin, false ) ); &m_PlotPanel.hpgl_origin, 0 ) );
m_params.emplace_back( new PARAM<int>( "simulator.window.pos_x", m_params.emplace_back( new PARAM<int>( "simulator.window.pos_x",
&m_Simulator.window.state.pos_x, 0 ) ); &m_Simulator.window.state.pos_x, 0 ) );

View File

@ -159,7 +159,7 @@ public:
bool frame_reference; bool frame_reference;
int hpgl_paper_size; int hpgl_paper_size;
double hpgl_pen_size; double hpgl_pen_size;
bool hpgl_origin; int hpgl_origin;
}; };
struct PANEL_SYM_CHOOSER struct PANEL_SYM_CHOOSER

View File

@ -141,7 +141,7 @@ void DIALOG_PLOT_SCHEMATIC::createHPGLFile( bool aPlotAll, bool aPlotFrameRef,
wxPoint plotOffset; wxPoint plotOffset;
wxString msg; wxString msg;
if( GetPlotOriginCenter() ) if( GetPlotOriginAndUnits() == HPGL_PLOT_ORIGIN_AND_UNITS::PLOTTER_CENTER )
{ {
plotOffset.x = plotPage.GetWidthIU() / 2; plotOffset.x = plotPage.GetWidthIU() / 2;
plotOffset.y = -plotPage.GetHeightIU() / 2; plotOffset.y = -plotPage.GetHeightIU() / 2;
@ -161,7 +161,7 @@ void DIALOG_PLOT_SCHEMATIC::createHPGLFile( bool aPlotAll, bool aPlotFrameRef,
LOCALE_IO toggle; LOCALE_IO toggle;
if( Plot_1_Page_HPGL( plotFileName.GetFullPath(), screen, plotPage, aRenderSettings, if( Plot_1_Page_HPGL( plotFileName.GetFullPath(), screen, plotPage, aRenderSettings,
plotOffset, plot_scale, aPlotFrameRef ) ) plotOffset, plot_scale, aPlotFrameRef, GetPlotOriginAndUnits() ) )
{ {
msg.Printf( _( "Plot: \"%s\" OK.\n" ), plotFileName.GetFullPath() ); msg.Printf( _( "Plot: \"%s\" OK.\n" ), plotFileName.GetFullPath() );
reporter.Report( msg, RPT_SEVERITY_ACTION ); reporter.Report( msg, RPT_SEVERITY_ACTION );
@ -192,7 +192,8 @@ bool DIALOG_PLOT_SCHEMATIC::Plot_1_Page_HPGL( const wxString& aFileName,
RENDER_SETTINGS* aRenderSettings, RENDER_SETTINGS* aRenderSettings,
wxPoint aPlot0ffset, wxPoint aPlot0ffset,
double aScale, double aScale,
bool aPlotFrameRef ) bool aPlotFrameRef,
HPGL_PLOT_ORIGIN_AND_UNITS aOriginAndUnits )
{ {
HPGL_PLOTTER* plotter = new HPGL_PLOTTER(); HPGL_PLOTTER* plotter = new HPGL_PLOTTER();
// Currently, plot units are in decimil // Currently, plot units are in decimil
@ -206,6 +207,23 @@ bool DIALOG_PLOT_SCHEMATIC::Plot_1_Page_HPGL( const wxString& aFileName,
// TODO this could be configurable // TODO this could be configurable
plotter->SetTargetChordLength( Millimeter2iu( 0.6 ) ); plotter->SetTargetChordLength( Millimeter2iu( 0.6 ) );
switch( aOriginAndUnits )
{
case HPGL_PLOT_ORIGIN_AND_UNITS::PLOTTER_BOT_LEFT:
case HPGL_PLOT_ORIGIN_AND_UNITS::PLOTTER_CENTER:
default:
plotter->SetUserCoords( false );
break;
case HPGL_PLOT_ORIGIN_AND_UNITS::USER_FIT_PAGE:
plotter->SetUserCoords( true );
plotter->SetUserCoordsFit( false );
break;
case HPGL_PLOT_ORIGIN_AND_UNITS::USER_FIT_CONTENT:
plotter->SetUserCoords( true );
plotter->SetUserCoordsFit( true );
break;
}
// Init : // Init :
plotter->SetCreator( wxT( "Eeschema-HPGL" ) ); plotter->SetCreator( wxT( "Eeschema-HPGL" ) );