HPGL improvements and optimizations for physical plotters
- Sort HPGL plots for speed - Reduce HPGL circle precision for tiny circles - Teach HPGL plotter about filled rectangles
This commit is contained in:
parent
54d2748032
commit
4ce91d3e92
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -204,6 +204,10 @@
|
|||
#include "plotter_hpgl.h"
|
||||
|
||||
|
||||
/// Compute the distance between two DPOINT points.
|
||||
static double dpoint_dist( DPOINT a, DPOINT b );
|
||||
|
||||
|
||||
// The hpgl command to close a polygon def, fill it and plot outline:
|
||||
// PM 2; ends the polygon definition and closes it if not closed
|
||||
// FP; fills the polygon
|
||||
|
@ -215,8 +219,10 @@ 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 )
|
||||
: arcTargetChordLength( 0 ),
|
||||
arcMinChordDegrees( 5.0 ),
|
||||
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
|
||||
|
@ -238,6 +244,12 @@ void HPGL_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil,
|
|||
}
|
||||
|
||||
|
||||
void HPGL_PLOTTER::SetTargetChordLength( double chord_len )
|
||||
{
|
||||
arcTargetChordLength = userToDeviceSize( chord_len );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* At the start of the HPGL plot pen speed and number are requested
|
||||
*/
|
||||
|
@ -255,7 +267,7 @@ bool HPGL_PLOTTER::StartPlot()
|
|||
|
||||
|
||||
/**
|
||||
* HPGL end of plot: pen return and release
|
||||
* HPGL end of plot: sort and emit graphics, pen return and release
|
||||
*/
|
||||
bool HPGL_PLOTTER::EndPlot()
|
||||
{
|
||||
|
@ -263,47 +275,38 @@ bool HPGL_PLOTTER::EndPlot()
|
|||
fputs( "PU;", m_outputFile );
|
||||
|
||||
flushItem();
|
||||
if( m_items.size() > 0 ) {
|
||||
sortItems( m_items );
|
||||
|
||||
DPOINT loc = m_items.begin()->loc_start;
|
||||
bool pen_up = true;
|
||||
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;
|
||||
int current_pen = penNumber;
|
||||
|
||||
for( HPGL_ITEM const & item: m_items ) {
|
||||
if( item.loc_start != loc || pen_up ) {
|
||||
if( !pen_up ) {
|
||||
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
|
||||
);
|
||||
fprintf( m_outputFile, "PA %.0f,%.0f;", item.loc_start.x, item.loc_start.y );
|
||||
}
|
||||
|
||||
if( item.dashType != current_dash ) {
|
||||
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;
|
||||
}
|
||||
fputs( lineTypeCommand( item.dashType ), m_outputFile );
|
||||
}
|
||||
|
||||
if( item.pen != current_pen ) {
|
||||
if( !pen_up ) {
|
||||
if( item.pen != current_pen )
|
||||
{
|
||||
if( !pen_up )
|
||||
{
|
||||
fputs( "PU;", m_outputFile );
|
||||
pen_up = true;
|
||||
}
|
||||
|
@ -311,17 +314,32 @@ bool HPGL_PLOTTER::EndPlot()
|
|||
current_pen = item.pen;
|
||||
}
|
||||
|
||||
if( pen_up ) {
|
||||
if( pen_up && !item.lift_before )
|
||||
{
|
||||
fputs( "PD;", m_outputFile );
|
||||
pen_up = false;
|
||||
}
|
||||
else if( !pen_up && item.lift_before )
|
||||
{
|
||||
fputs( "PU;", m_outputFile );
|
||||
pen_up = true;
|
||||
}
|
||||
|
||||
fputs( item.content, m_outputFile );
|
||||
|
||||
if( item.lift_after ) {
|
||||
if( !item.pen_returns )
|
||||
{
|
||||
// Assume commands drop the pen
|
||||
pen_up = false;
|
||||
}
|
||||
|
||||
if( item.lift_after )
|
||||
{
|
||||
fputs( "PU;", m_outputFile );
|
||||
pen_up = true;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
loc = item.loc_end;
|
||||
}
|
||||
fputs( "\n", m_outputFile );
|
||||
|
@ -340,26 +358,23 @@ void HPGL_PLOTTER::SetPenDiameter( double diameter )
|
|||
penDiameter = diameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* HPGL rectangle: fill not supported
|
||||
*/
|
||||
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 );
|
||||
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;
|
||||
if( fill == FILL_TYPE::FILLED_SHAPE )
|
||||
{
|
||||
startOrAppendItem( p1dev, wxString::Format( "RA %.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;
|
||||
PenFinish();
|
||||
}
|
||||
|
||||
|
@ -373,30 +388,36 @@ void HPGL_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_TYPE fill,
|
|||
DPOINT center_dev = userToDeviceCoordinates( centre );
|
||||
SetCurrentLineWidth( width );
|
||||
|
||||
double const circumf = 2.0 * M_PI * radius;
|
||||
double const target_chord_length = arcTargetChordLength;
|
||||
double chord_degrees = 360.0 * target_chord_length / circumf;
|
||||
|
||||
if( chord_degrees < arcMinChordDegrees )
|
||||
{
|
||||
chord_degrees = arcMinChordDegrees;
|
||||
}
|
||||
else if( chord_degrees > 45 )
|
||||
{
|
||||
chord_degrees = 45;
|
||||
}
|
||||
|
||||
if( fill == FILL_TYPE::FILLED_SHAPE )
|
||||
{
|
||||
// Draw the filled area
|
||||
MoveTo( centre );
|
||||
startOrAppendItem(
|
||||
center_dev,
|
||||
wxString::Format(
|
||||
"PM 0;CI %g;%s", radius, hpgl_end_polygon_cmd
|
||||
)
|
||||
);
|
||||
m_current_item->lift_after = true;
|
||||
startOrAppendItem( center_dev, wxString::Format( "PM 0;CI %g,%g;%s", radius, chord_degrees,
|
||||
hpgl_end_polygon_cmd ) );
|
||||
m_current_item->lift_before = true;
|
||||
m_current_item->pen_returns = true;
|
||||
PenFinish();
|
||||
}
|
||||
|
||||
if( radius > 0 )
|
||||
{
|
||||
MoveTo( centre );
|
||||
startOrAppendItem(
|
||||
center_dev,
|
||||
wxString::Format(
|
||||
"CI %g;", radius
|
||||
)
|
||||
);
|
||||
m_current_item->lift_after = true;
|
||||
startOrAppendItem( center_dev, wxString::Format( "CI %g,%g;", radius, chord_degrees ) );
|
||||
m_current_item->lift_before = true;
|
||||
m_current_item->pen_returns = true;
|
||||
PenFinish();
|
||||
}
|
||||
}
|
||||
|
@ -439,7 +460,7 @@ void HPGL_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList,
|
|||
LineTo( aCornerList[0] );
|
||||
|
||||
m_current_item->content << hpgl_end_polygon_cmd; // Close, fill polygon and draw outlines
|
||||
m_current_item->lift_after = true;
|
||||
m_current_item->pen_returns = true;
|
||||
}
|
||||
else if( aWidth > 0 )
|
||||
{
|
||||
|
@ -461,71 +482,28 @@ void HPGL_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pen control logic (remove redundant pen activations)
|
||||
*/
|
||||
void HPGL_PLOTTER::penControl( char plume )
|
||||
{
|
||||
m_penState = plume;
|
||||
/*
|
||||
wxASSERT( m_outputFile );
|
||||
|
||||
switch( plume )
|
||||
{
|
||||
case 'U':
|
||||
|
||||
if( m_penState != 'U' )
|
||||
{
|
||||
fputs( "PU;", m_outputFile );
|
||||
m_penState = 'U';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
|
||||
if( m_penState != 'D' )
|
||||
{
|
||||
fputs( "PD;", m_outputFile );
|
||||
m_penState = 'D';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
fputs( "PU;", m_outputFile );
|
||||
m_penState = 'U';
|
||||
m_penLastpos.x = -1;
|
||||
m_penLastpos.y = -1;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void HPGL_PLOTTER::PenTo( const wxPoint& pos, char plume )
|
||||
{
|
||||
wxASSERT( m_outputFile );
|
||||
|
||||
if( plume == 'Z' )
|
||||
{
|
||||
penControl( 'Z' );
|
||||
m_penState = 'Z';
|
||||
flushItem();
|
||||
return;
|
||||
}
|
||||
|
||||
penControl( plume );
|
||||
DPOINT pos_dev = userToDeviceCoordinates( pos );
|
||||
DPOINT lastpos_dev = userToDeviceCoordinates( m_penLastpos );
|
||||
|
||||
if( plume == 'U' )
|
||||
{
|
||||
penControl( 'U' );
|
||||
m_penState = 'U';
|
||||
flushItem();
|
||||
}
|
||||
else if( plume == 'D' )
|
||||
{
|
||||
penControl( 'D' );
|
||||
m_penState = 'D';
|
||||
startOrAppendItem(
|
||||
lastpos_dev,
|
||||
wxString::Format(
|
||||
|
@ -547,24 +525,7 @@ void HPGL_PLOTTER::PenTo( const wxPoint& pos, char plume )
|
|||
void HPGL_PLOTTER::SetDash( PLOT_DASH_TYPE dashed )
|
||||
{
|
||||
dashType = dashed;
|
||||
/*
|
||||
wxASSERT( m_outputFile );
|
||||
|
||||
switch( dashed )
|
||||
{
|
||||
case PLOT_DASH_TYPE::DASH:
|
||||
fprintf( m_outputFile, "LT -2 4 1;\n" );
|
||||
break;
|
||||
case PLOT_DASH_TYPE::DOT:
|
||||
fprintf( m_outputFile, "LT -1 2 1;\n" );
|
||||
break;
|
||||
case PLOT_DASH_TYPE::DASHDOT:
|
||||
fprintf( m_outputFile, "LT -4 6 1;\n" );
|
||||
break;
|
||||
default:
|
||||
fputs( "LT;\n", m_outputFile );
|
||||
}
|
||||
*/
|
||||
flushItem();
|
||||
}
|
||||
|
||||
|
||||
|
@ -603,6 +564,19 @@ 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 target_chord_length = arcTargetChordLength;
|
||||
double chord_degrees = 360.0 * target_chord_length / circumf;
|
||||
|
||||
if( chord_degrees < arcMinChordDegrees )
|
||||
{
|
||||
chord_degrees = arcMinChordDegrees;
|
||||
}
|
||||
else if( chord_degrees > 45 )
|
||||
{
|
||||
chord_degrees = 45;
|
||||
}
|
||||
|
||||
DPOINT centre_dev = userToDeviceCoordinates( centre );
|
||||
|
||||
if( m_plotMirror )
|
||||
|
@ -619,13 +593,8 @@ void HPGL_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle,
|
|||
cmap.y = centre.y - KiROUND( sindecideg( radius, StAngle ) );
|
||||
DPOINT cmap_dev = userToDeviceCoordinates( cmap );
|
||||
|
||||
startOrAppendItem(
|
||||
cmap_dev,
|
||||
wxString::Format(
|
||||
"AA %.0f,%.0f",
|
||||
centre_dev.x, centre_dev.y
|
||||
)
|
||||
);
|
||||
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...
|
||||
m_current_item->lift_after = true;
|
||||
|
@ -699,21 +668,18 @@ 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
|
||||
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
|
||||
)
|
||||
);
|
||||
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 ) );
|
||||
m_current_item->lift_before = true;
|
||||
m_current_item->pen_returns = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw outline only:
|
||||
startOrAppendItem(
|
||||
pos_dev,
|
||||
wxString::Format( "CI %.0f;", rsize )
|
||||
);
|
||||
startOrAppendItem( pos_dev, wxString::Format( "CI %.0f;", rsize ) );
|
||||
m_current_item->lift_before = true;
|
||||
m_current_item->pen_returns = true;
|
||||
}
|
||||
|
||||
PenFinish();
|
||||
|
@ -855,28 +821,113 @@ bool HPGL_PLOTTER::startItem( DPOINT location )
|
|||
}
|
||||
|
||||
|
||||
void HPGL_PLOTTER::flushItem( )
|
||||
void HPGL_PLOTTER::flushItem()
|
||||
{
|
||||
m_current_item = nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool HPGL_PLOTTER::startOrAppendItem( DPOINT location, wxString const & content )
|
||||
bool HPGL_PLOTTER::startOrAppendItem( DPOINT location, wxString const& content )
|
||||
{
|
||||
if( m_current_item == nullptr ) {
|
||||
HPGL_ITEM item = {
|
||||
location,
|
||||
location,
|
||||
false,
|
||||
penNumber,
|
||||
dashType,
|
||||
content
|
||||
};
|
||||
if( m_current_item == nullptr )
|
||||
{
|
||||
HPGL_ITEM item = { location, location, false, false, false, penNumber, dashType, content };
|
||||
m_items.push_back( item );
|
||||
m_current_item = &m_items.back();
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
m_current_item->content << content;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void HPGL_PLOTTER::sortItems( std::list<HPGL_ITEM>& items )
|
||||
{
|
||||
if( items.size() < 2 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::list<HPGL_ITEM> target;
|
||||
|
||||
// Plot items are sorted to improve print time on mechanical plotters. This
|
||||
// means
|
||||
// 1) Avoid excess pen-switching - once a pen is selected, keep printing
|
||||
// with it until no more items using that pen remain.
|
||||
// 2) Within the items for one pen, avoid bouncing back and forth around
|
||||
// the page; items should be sequenced with nearby items.
|
||||
//
|
||||
// This is essentially a variant of the Travelling Salesman Problem where
|
||||
// the cities are themselves edges that must be traversed. This is of course
|
||||
// a famously NP-Hard problem and this particular variant has a monstrous
|
||||
// number of "cities". For now, we're using a naive nearest-neighbor search,
|
||||
// which is less than optimal but (usually!) better than nothing, very
|
||||
// simple to implement, and fast enough.
|
||||
//
|
||||
// Items are moved one at a time from `items` into `target`, searching
|
||||
// each time for the first one matching the above criteria. Then, all of
|
||||
// `target` is moved back into `items`.
|
||||
|
||||
// Get the first one started
|
||||
HPGL_ITEM last_item = items.front();
|
||||
items.pop_front();
|
||||
target.emplace_back( last_item );
|
||||
|
||||
while( !items.empty() )
|
||||
{
|
||||
auto best_it = items.begin();
|
||||
double best_dist = dpoint_dist( last_item.loc_end, best_it->loc_start );
|
||||
|
||||
for( auto search_it = best_it; search_it != items.end(); search_it++ )
|
||||
{
|
||||
// Immediately forget an item as "best" if another one is a better
|
||||
// pen match
|
||||
if( best_it->pen != last_item.pen && search_it->pen == last_item.pen )
|
||||
{
|
||||
best_it = search_it;
|
||||
continue;
|
||||
}
|
||||
|
||||
double const dist = dpoint_dist( last_item.loc_end, search_it->loc_start );
|
||||
if( dist < best_dist )
|
||||
{
|
||||
best_it = search_it;
|
||||
best_dist = dist;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
target.emplace_back( *best_it );
|
||||
last_item = *best_it;
|
||||
items.erase( best_it );
|
||||
}
|
||||
|
||||
items.splice( items.begin(), target );
|
||||
}
|
||||
|
||||
wxString HPGL_PLOTTER::lineTypeCommand( PLOT_DASH_TYPE linetype )
|
||||
{
|
||||
switch( linetype )
|
||||
{
|
||||
case PLOT_DASH_TYPE::DASH:
|
||||
return "LT -2 4 1;";
|
||||
break;
|
||||
case PLOT_DASH_TYPE::DOT:
|
||||
return "LT -1 2 1;";
|
||||
break;
|
||||
case PLOT_DASH_TYPE::DASHDOT:
|
||||
return "LT -4 6 1;";
|
||||
break;
|
||||
default:
|
||||
return "LT;";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static double dpoint_dist( DPOINT a, DPOINT b )
|
||||
{
|
||||
DPOINT diff = a - b;
|
||||
return sqrt( diff.x * diff.x + diff.y * diff.y );
|
||||
}
|
||||
|
|
|
@ -25,10 +25,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <eda_item.h> // FILL_TYPE
|
||||
#include <math/box2.h>
|
||||
#include <eda_item.h> // FILL_TYPE
|
||||
#include <plotter.h>
|
||||
|
||||
|
||||
|
@ -47,6 +48,12 @@ public:
|
|||
return wxString( wxT( "plt" ) );
|
||||
}
|
||||
|
||||
/// Set the target length of chords used to draw approximated circles and
|
||||
/// arcs.
|
||||
///
|
||||
/// @param chord_len - chord length in IUs
|
||||
void SetTargetChordLength( double chord_len );
|
||||
|
||||
virtual bool StartPlot() override;
|
||||
virtual bool EndPlot() override;
|
||||
|
||||
|
@ -107,8 +114,6 @@ public:
|
|||
double aOrient, OUTLINE_MODE aTraceMode, void* aData ) override;
|
||||
|
||||
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
|
||||
|
@ -117,7 +122,7 @@ protected:
|
|||
bool startItem( DPOINT location );
|
||||
|
||||
/// Flush the current HPGL_ITEM and clear out the current item pointer.
|
||||
void flushItem( );
|
||||
void flushItem();
|
||||
|
||||
/// Start a new HPGL_ITEM with the given string if necessary, or append the
|
||||
/// string to the current item.
|
||||
|
@ -126,25 +131,56 @@ protected:
|
|||
/// @param content - content substring
|
||||
///
|
||||
/// @return whether a new item was made
|
||||
bool startOrAppendItem( DPOINT location, wxString const & content );
|
||||
bool startOrAppendItem( DPOINT location, wxString const& content );
|
||||
|
||||
int penSpeed;
|
||||
int penNumber;
|
||||
double penDiameter;
|
||||
double arcTargetChordLength;
|
||||
double arcMinChordDegrees;
|
||||
PLOT_DASH_TYPE dashType;
|
||||
|
||||
struct HPGL_ITEM
|
||||
{
|
||||
DPOINT loc_start;
|
||||
DPOINT loc_end;
|
||||
bool lift_after;
|
||||
int pen;
|
||||
/// Location the pen should start at
|
||||
DPOINT loc_start;
|
||||
|
||||
/// Location the pen will be at when it finishes. If this is not known,
|
||||
/// leave it equal to loc_start and set lift_after.
|
||||
DPOINT loc_end;
|
||||
|
||||
/// Whether the command should be executed with the pen lifted
|
||||
bool lift_before;
|
||||
|
||||
/// Whether the pen must be lifted after the command. If the location of the pen
|
||||
/// is not known, this must be set (so that another command starting at loc_end
|
||||
/// is not immediately executed with no lift).
|
||||
bool lift_after;
|
||||
|
||||
/// Whether the pen returns to its original state after the command. Otherwise,
|
||||
/// the pen is assumed to be down following the command.
|
||||
bool pen_returns;
|
||||
|
||||
/// Pen number for this command
|
||||
int pen;
|
||||
|
||||
/// Line style for this command
|
||||
PLOT_DASH_TYPE dashType;
|
||||
wxString content;
|
||||
|
||||
/// Text of the command
|
||||
wxString content;
|
||||
};
|
||||
|
||||
/// Sort a list of HPGL items to improve plotting speed on mechanical plotters.
|
||||
///
|
||||
/// @param items - items to sort
|
||||
static void sortItems( std::list<HPGL_ITEM>& items );
|
||||
|
||||
/// Return the plot command corresponding to a line type
|
||||
static wxString lineTypeCommand( PLOT_DASH_TYPE linetype );
|
||||
|
||||
std::list<HPGL_ITEM> m_items;
|
||||
HPGL_ITEM * m_current_item;
|
||||
HPGL_ITEM* m_current_item;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -203,6 +203,9 @@ bool DIALOG_PLOT_SCHEMATIC::Plot_1_Page_HPGL( const wxString& aFileName,
|
|||
plotter->SetColorMode( getModeColor() );
|
||||
plotter->SetViewport( aPlot0ffset, IU_PER_MILS/10, aScale, false );
|
||||
|
||||
// TODO this could be configurable
|
||||
plotter->SetTargetChordLength( Millimeter2iu( 0.6 ) );
|
||||
|
||||
// Init :
|
||||
plotter->SetCreator( wxT( "Eeschema-HPGL" ) );
|
||||
|
||||
|
|
Loading…
Reference in New Issue