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 ),
arcMinChordDegrees( 5.0 ),
dashType( PLOT_DASH_TYPE::SOLID ),
useUserCoords( false ),
fitUserCoords( false ),
m_current_item( nullptr )
{
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()
{
wxASSERT( m_outputFile );
fputs( "PU;", m_outputFile );
fputs( "PU;\n", m_outputFile );
flushItem();
sortItems( m_items );
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;
bool pen_up = true;
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 ) );
m_current_item->loc_end = m_current_item->loc_start;
m_current_item->bbox.Merge( p2dev );
PenFinish();
}
@ -410,6 +434,9 @@ void HPGL_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_TYPE fill,
hpgl_end_polygon_cmd ) );
m_current_item->lift_before = true;
m_current_item->pen_returns = true;
m_current_item->bbox.Merge(
BOX2D( center_dev - radius, VECTOR2D( 2 * radius, 2 * radius ) )
);
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 ) );
m_current_item->lift_before = true;
m_current_item->pen_returns = true;
m_current_item->bbox.Merge(
BOX2D( center_dev - radius, VECTOR2D( 2 * radius, 2 * radius ) )
);
PenFinish();
}
}
@ -514,6 +544,7 @@ void HPGL_PLOTTER::PenTo( const wxPoint& pos, char plume )
)
);
m_current_item->loc_end = pos_dev;
m_current_item->bbox.Merge( pos_dev );
}
m_penLastpos = pos;
@ -565,9 +596,10 @@ void HPGL_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle,
if( radius <= 0 )
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 chord_degrees = 360.0 * target_chord_length / circumf;
double chord_degrees = 360.0 * target_chord_length / circumf_dev;
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,
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;
flushItem();
}
@ -832,7 +867,13 @@ bool HPGL_PLOTTER::startOrAppendItem( DPOINT location, wxString const& content )
{
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_current_item = &m_items.back();
return true;

View File

@ -54,6 +54,18 @@ public:
/// @param chord_len - chord length in IUs
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 EndPlot() override;
@ -133,15 +145,24 @@ protected:
/// @return whether a new item was made
bool startOrAppendItem( DPOINT location, wxString const& content );
int penSpeed;
int penNumber;
double penDiameter;
int penSpeed;
int penNumber;
double penDiameter;
double arcTargetChordLength;
double arcMinChordDegrees;
PLOT_DASH_TYPE dashType;
bool useUserCoords;
bool fitUserCoords;
struct HPGL_ITEM
{
HPGL_ITEM()
: lift_before( false ),
lift_after( false ),
pen_returns( false ),
pen( 0 )
{}
/// Location the pen should start at
DPOINT loc_start;
@ -149,6 +170,9 @@ protected:
/// leave it equal to loc_start and set lift_after.
DPOINT loc_end;
/// Bounding box of this item
BOX2D bbox;
/// Whether the command should be executed with the pen lifted
bool lift_before;

View File

@ -96,8 +96,8 @@ void DIALOG_PLOT_SCHEMATIC::initDlg()
// Set plot or not frame reference option
setPlotFrameRef( cfg->m_PlotPanel.frame_reference );
// Set HPGL plot origin to center of paper of left bottom corner
SetPlotOriginCenter( cfg->m_PlotPanel.hpgl_origin );
// HPGL plot origin and unit system configuration
m_plotOriginOpt->SetSelection( cfg->m_PlotPanel.hpgl_origin );
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.frame_reference = getPlotFrameRef();
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;
// HPGL Pen Size is stored in mm in config

View File

@ -40,6 +40,13 @@ enum PageFormatReq {
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 DIALOG_PLOT_SCHEMATIC : public DIALOG_PLOT_SCHEMATIC_BASE
@ -112,21 +119,48 @@ private:
wxPoint aPlot0ffset, double aScale, bool aPlotFrameRef );
// 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 SetHPGLPenWidth();
bool Plot_1_Page_HPGL( const wxString& aFileName, SCH_SCREEN* aScreen,
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
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->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 );
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 );
m_plotOriginOpt = new wxChoice( m_HPGLOptionsSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_plotOriginOptNChoices, m_plotOriginOptChoices, 0 );
m_plotOriginOpt->SetSelection( 0 );

View File

@ -1164,7 +1164,7 @@
<property name="gripper">0</property>
<property name="hidden">0</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="max_size"></property>
<property name="maximize_button">0</property>
@ -1214,7 +1214,7 @@
<property name="caption"></property>
<property name="caption_visible">1</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="context_help"></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_PlotPanel.hpgl_pen_size, 0.5 ) );
m_params.emplace_back( new PARAM<bool>( "plot.hpgl_origin",
&m_PlotPanel.hpgl_origin, false ) );
m_params.emplace_back( new PARAM<int>( "plot.hpgl_origin",
&m_PlotPanel.hpgl_origin, 0 ) );
m_params.emplace_back( new PARAM<int>( "simulator.window.pos_x",
&m_Simulator.window.state.pos_x, 0 ) );

View File

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

View File

@ -141,7 +141,7 @@ void DIALOG_PLOT_SCHEMATIC::createHPGLFile( bool aPlotAll, bool aPlotFrameRef,
wxPoint plotOffset;
wxString msg;
if( GetPlotOriginCenter() )
if( GetPlotOriginAndUnits() == HPGL_PLOT_ORIGIN_AND_UNITS::PLOTTER_CENTER )
{
plotOffset.x = plotPage.GetWidthIU() / 2;
plotOffset.y = -plotPage.GetHeightIU() / 2;
@ -161,7 +161,7 @@ void DIALOG_PLOT_SCHEMATIC::createHPGLFile( bool aPlotAll, bool aPlotFrameRef,
LOCALE_IO toggle;
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() );
reporter.Report( msg, RPT_SEVERITY_ACTION );
@ -192,7 +192,8 @@ bool DIALOG_PLOT_SCHEMATIC::Plot_1_Page_HPGL( const wxString& aFileName,
RENDER_SETTINGS* aRenderSettings,
wxPoint aPlot0ffset,
double aScale,
bool aPlotFrameRef )
bool aPlotFrameRef,
HPGL_PLOT_ORIGIN_AND_UNITS aOriginAndUnits )
{
HPGL_PLOTTER* plotter = new HPGL_PLOTTER();
// 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
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 :
plotter->SetCreator( wxT( "Eeschema-HPGL" ) );