kicad/common/common_plotHPGL_functions.cpp

549 lines
14 KiB
C++

/************************************/
/* Kicad: Common plot HPGL Routines */
/************************************/
#include "fctsys.h"
#include "gr_basic.h"
#include "trigo.h"
#include "wxstruct.h"
#include "base_struct.h"
#include "plot_common.h"
#include "macros.h"
#include "kicad_string.h"
/* HPGL scale factor. */
const double SCALE_HPGL = 0.102041;
/* Set the plot offset for the current plotting
*/
void HPGL_PLOTTER::set_viewport( wxPoint offset, double aScale, int orient )
{
wxASSERT( !output_file );
plot_offset = offset;
plot_scale = aScale;
device_scale = SCALE_HPGL;
set_default_line_width( 100 ); /* default line width in 1 / 1000 inch */
plot_orient_options = orient;
}
bool HPGL_PLOTTER::start_plot( FILE* fout )
{
wxASSERT( !output_file );
output_file = fout;
fprintf( output_file, "IN;VS%d;PU;PA;SP%d;\n", pen_speed, pen_number );
return true;
}
bool HPGL_PLOTTER::end_plot()
{
wxASSERT( output_file );
fputs( "PU;PA;SP0;\n", output_file );
fclose( output_file );
output_file = NULL;
return true;
}
void HPGL_PLOTTER::rect( wxPoint p1, wxPoint p2, FILL_T fill, int width )
{
wxASSERT( output_file );
user_to_device_coordinates( p2 );
move_to( p1 );
fprintf( output_file, "EA %d,%d;\n", p2.x, p2.y );
pen_finish();
}
void HPGL_PLOTTER::circle( wxPoint centre,
int diameter,
FILL_T fill,
int width )
{
wxASSERT( output_file );
double rayon = user_to_device_size( diameter / 2 );
if( rayon > 0 )
{
move_to( centre );
fprintf( output_file, "CI %g;\n", rayon );
pen_finish();
}
}
/* Plot a polygon (closed if completed) in HPGL
* Coord = coord table tops
* Nb = number of coord (coord 1 = 2 elements: X and Y table)
* Fill: if! = 0 filled polygon
*/
void HPGL_PLOTTER::poly( int nb, int* coord, FILL_T fill, int width )
{
wxASSERT( output_file );
if( nb <= 1 )
return;
move_to( wxPoint( coord[0], coord[1] ) );
for( int ii = 1; ii < nb; ii++ )
line_to( wxPoint( coord[ii * 2], coord[(ii * 2) + 1] ) );
/* Close polygon if filled. */
if( fill )
{
int ii = (nb - 1) * 2;
if( (coord[ii] != coord[0] ) || (coord[ii + 1] != coord[1]) )
line_to( wxPoint( coord[0], coord[1] ) );
}
pen_finish();
}
/* Set pen up ('U') or down ('D').
*/
void HPGL_PLOTTER::pen_control( int plume )
{
wxASSERT( output_file );
switch( plume )
{
case 'U':
if( pen_state != 'U' )
{
fputs( "PU;", output_file );
pen_state = 'U';
}
break;
case 'D':
if( pen_state != 'D' )
{
fputs( "PD;", output_file );
pen_state = 'D';
}
break;
case 'Z':
fputs( "PU;", output_file );
pen_state = 'U';
pen_lastpos.x = -1;
pen_lastpos.y = -1;
break;
}
}
/*
* Move the pen to position with pen up or down.
* At position x, y
* Unit to unit DRAWING
* If pen = 'Z' without changing pen during move.
*/
void HPGL_PLOTTER::pen_to( wxPoint pos, char plume )
{
wxASSERT( output_file );
if( plume == 'Z' )
{
pen_control( 'Z' );
return;
}
pen_control( plume );
user_to_device_coordinates( pos );
if( pen_lastpos != pos )
fprintf( output_file, "PA %d,%d;\n", pos.x, pos.y );
pen_lastpos = pos;
}
void HPGL_PLOTTER::set_dash( bool dashed )
{
wxASSERT( output_file );
if( dashed )
fputs( "LI 2;\n", stderr );
else
fputs( "LI;\n", stderr );
}
/**
* Function Plot a filled segment (track)
* @param start = starting point
* @param end = ending point
* @param aWidth = segment width (thickness)
* @param aPlotMode = FILLED, SKETCH ..
*/
void HPGL_PLOTTER::thick_segment( wxPoint start, wxPoint end, int width,
GRTraceMode tracemode )
{
wxASSERT( output_file );
wxPoint center;
wxSize size;
if( (pen_diameter >= width) || (tracemode == FILAIRE) ) /* just a line is
* Ok */
{
move_to( start );
finish_to( end );
}
else
segment_as_oval( start, end, width, tracemode );
}
/* Plot an arc:
* Center = center coord
* Stangl, endAngle = angle of beginning and end
* Radius = radius of the arc
* Command
* PU PY x, y; PD start_arc_X AA, start_arc_Y, angle, NbSegm; PU;
* Or PU PY x, y; PD start_arc_X AA, start_arc_Y, angle, PU;
*/
void HPGL_PLOTTER::arc( wxPoint centre, int StAngle, int EndAngle, int rayon,
FILL_T fill, int width )
{
wxASSERT( output_file );
wxPoint cmap;
wxPoint cpos;
float angle;
if( rayon <= 0 )
return;
cpos = centre;
user_to_device_coordinates( cpos );
if( plot_orient_options == PLOT_MIROIR )
angle = (StAngle - EndAngle) / 10.0;
else
angle = (EndAngle - StAngle) / 10.0;
/* Calculate start point, */
cmap.x = (int) ( centre.x + ( rayon * cos( StAngle * M_PI / 1800 ) ) );
cmap.y = (int) ( centre.y - ( rayon * sin( StAngle * M_PI / 1800 ) ) );
user_to_device_coordinates( cmap );
fprintf( output_file,
"PU;PA %d,%d;PD;AA %d,%d, ",
cmap.x,
cmap.y,
cpos.x,
cpos.y );
fprintf( output_file, "%f", angle );
fprintf( output_file, ";PU;\n" );
pen_finish();
}
/* Plot oval pad.
*/
void HPGL_PLOTTER::flash_pad_oval( wxPoint pos, wxSize size, int orient,
GRTraceMode trace_mode )
{
wxASSERT( output_file );
int rayon, deltaxy, cx, cy;
/* The pad is reduced to an oval with size.y > size.x
* (Oval vertical orientation 0)
*/
if( size.x > size.y )
{
EXCHG( size.x, size.y ); orient += 900;
if( orient >= 3600 )
orient -= 3600;
}
deltaxy = size.y - size.x; /* distance between centers of the oval */
rayon = size.x / 2;
if( trace_mode == FILLED )
{
flash_pad_rect( pos, wxSize( size.x, deltaxy + wxRound( pen_diameter ) ),
orient, trace_mode );
cx = 0; cy = deltaxy / 2;
RotatePoint( &cx, &cy, orient );
flash_pad_circle( wxPoint( cx + pos.x,
cy + pos.y ), size.x, trace_mode );
cx = 0; cy = -deltaxy / 2;
RotatePoint( &cx, &cy, orient );
flash_pad_circle( wxPoint( cx + pos.x,
cy + pos.y ), size.x, trace_mode );
}
else /* Plot in SKETCH mode. */
{
sketch_oval( pos, size, orient, wxRound( pen_diameter ) );
}
}
/* Plot round pad or via.
*/
void HPGL_PLOTTER::flash_pad_circle( wxPoint pos, int diametre,
GRTraceMode trace_mode )
{
wxASSERT( output_file );
int rayon, delta;
user_to_device_coordinates( pos );
delta = wxRound( pen_diameter - pen_overlap );
rayon = diametre / 2;
if( trace_mode != FILAIRE )
{
rayon = ( diametre - wxRound( pen_diameter ) ) / 2;
}
if( rayon < 0 )
{
rayon = 0;
}
wxSize rsize( rayon, rayon );
user_to_device_size( rsize );
fprintf( output_file, "PA %d,%d;CI %d;\n", pos.x, pos.y, rsize.x );
if( trace_mode == FILLED ) /* Plot in filled mode. */
{
if( delta > 0 )
{
while( (rayon -= delta ) >= 0 )
{
rsize.x = rsize.y = rayon;
user_to_device_size( rsize );
fprintf( output_file,
"PA %d,%d; CI %d;\n",
pos.x,
pos.y,
rsize.x );
}
}
}
pen_finish();
return;
}
/*
* Plot rectangular pad vertical or horizontal.
* Gives its center and its dimensions X and Y
* Units are user units
*/
void HPGL_PLOTTER::flash_pad_rect( wxPoint pos, wxSize padsize,
int orient, GRTraceMode trace_mode )
{
wxASSERT( output_file );
wxSize size;
int delta;
int ox, oy, fx, fy;
size.x = padsize.x / 2;
size.y = padsize.y / 2;
if( trace_mode != FILAIRE )
{
size.x = (padsize.x - (int) pen_diameter) / 2;
size.y = (padsize.y - (int) pen_diameter) / 2;
}
if( size.x < 0 )
size.x = 0;
if( size.y < 0 )
size.y = 0;
/* If a dimension is zero, the trace is reduced to 1 line. */
if( size.x == 0 )
{
ox = pos.x;
oy = pos.y - size.y;
RotatePoint( &ox, &oy, pos.x, pos.y, orient );
fx = pos.x;
fy = pos.y + size.y;
RotatePoint( &fx, &fy, pos.x, pos.y, orient );
move_to( wxPoint( ox, oy ) );
finish_to( wxPoint( fx, fy ) );
return;
}
if( size.y == 0 )
{
ox = pos.x - size.x;
oy = pos.y;
RotatePoint( &ox, &oy, pos.x, pos.y, orient );
fx = pos.x + size.x;
fy = pos.y;
RotatePoint( &fx, &fy, pos.x, pos.y, orient );
move_to( wxPoint( ox, oy ) );
finish_to( wxPoint( fx, fy ) );
return;
}
ox = pos.x - size.x;
oy = pos.y - size.y;
RotatePoint( &ox, &oy, pos.x, pos.y, orient );
move_to( wxPoint( ox, oy ) );
fx = pos.x - size.x;
fy = pos.y + size.y;
RotatePoint( &fx, &fy, pos.x, pos.y, orient );
line_to( wxPoint( fx, fy ) );
fx = pos.x + size.x;
fy = pos.y + size.y;
RotatePoint( &fx, &fy, pos.x, pos.y, orient );
line_to( wxPoint( fx, fy ) );
fx = pos.x + size.x;
fy = pos.y - size.y;
RotatePoint( &fx, &fy, pos.x, pos.y, orient );
line_to( wxPoint( fx, fy ) );
finish_to( wxPoint( ox, oy ) );
if( trace_mode == FILLED )
{
/* Plot in filled mode. */
delta = (int) (pen_diameter - pen_overlap);
if( delta > 0 )
while( (size.x > 0) && (size.y > 0) )
{
size.x -= delta;
size.y -= delta;
if( size.x < 0 )
size.x = 0;
if( size.y < 0 )
size.y = 0;
ox = pos.x - size.x;
oy = pos.y - size.y;
RotatePoint( &ox, &oy, pos.x, pos.y, orient );
move_to( wxPoint( ox, oy ) );
fx = pos.x - size.x;
fy = pos.y + size.y;
RotatePoint( &fx, &fy, pos.x, pos.y, orient );
line_to( wxPoint( fx, fy ) );
fx = pos.x + size.x;
fy = pos.y + size.y;
RotatePoint( &fx, &fy, pos.x, pos.y, orient );
line_to( wxPoint( fx, fy ) );
fx = pos.x + size.x;
fy = pos.y - size.y;
RotatePoint( &fx, &fy, pos.x, pos.y, orient );
line_to( wxPoint( fx, fy ) );
finish_to( wxPoint( ox, oy ) );
}
}
}
/* Plot trapezoidal pad.
* aPadPos is pad position, aCorners the corners position of the basic shape
* Orientation aPadOrient in 0.1 degrees
* Plot mode FILLED or SKETCH
*/
void HPGL_PLOTTER::flash_pad_trapez( wxPoint aPadPos, wxPoint aCorners[4],
int aPadOrient, GRTraceMode aTrace_Mode )
{
wxASSERT( output_file );
wxPoint polygone[4]; // coordinates of corners relatives to the pad
wxPoint coord[4]; // absolute coordinates of corners (coordinates in plotter space)
int move;
move = wxRound( pen_diameter );
for( int ii = 0; ii < 4; ii++ )
polygone[ii] = aCorners[ii];
// polygone[0] is assumed the lower left
// polygone[1] is assumed the upper left
// polygone[2] is assumed the upper right
// polygone[3] is assumed the lower right
// Plot the outline:
for( int ii = 0; ii < 4; ii++ )
{
coord[ii] = polygone[ii];
RotatePoint( &coord[ii], aPadOrient );
coord[ii] += aPadPos;
}
move_to( coord[0] );
line_to( coord[1] );
line_to( coord[2] );
line_to( coord[3] );
finish_to( coord[0] );
// Fill shape:
if( aTrace_Mode == FILLED )
{
// TODO: replace this par the HPGL plot polygon.
int jj;
/* Fill the shape */
move = wxRound( pen_diameter - pen_overlap );
/* Calculate fill height. */
if( polygone[0].y == polygone[3].y ) /* Horizontal */
{
jj = polygone[3].y - (int) ( pen_diameter + ( 2 * pen_overlap ) );
}
else // vertical
{
jj = polygone[3].x - (int) ( pen_diameter + ( 2 * pen_overlap ) );
}
/* Calculation of dd = number of segments was traced to fill. */
jj = jj / (int) ( pen_diameter - pen_overlap );
/* Trace the outline. */
for( ; jj > 0; jj-- )
{
polygone[0].x += move;
polygone[0].y -= move;
polygone[1].x += move;
polygone[1].y += move;
polygone[2].x -= move;
polygone[2].y += move;
polygone[3].x -= move;
polygone[3].y -= move;
/* Test for crossed vertexes. */
if( polygone[0].x > polygone[3].x ) /* X axis intersection on
*vertexes 0 and 3 */
{
polygone[0].x = polygone[3].x = 0;
}
if( polygone[1].x > polygone[2].x ) /* X axis intersection on
*vertexes 1 and 2 */
{
polygone[1].x = polygone[2].x = 0;
}
if( polygone[1].y > polygone[0].y ) /* Y axis intersection on
*vertexes 0 and 1 */
{
polygone[0].y = polygone[1].y = 0;
}
if( polygone[2].y > polygone[3].y ) /* Y axis intersection on
*vertexes 2 and 3 */
{
polygone[2].y = polygone[3].y = 0;
}
for( int ii = 0; ii < 4; ii++ )
{
coord[ii] = polygone[ii];
RotatePoint( &coord[ii], aPadOrient );
coord[ii] += aPadPos;
}
move_to( coord[0] );
line_to( coord[1] );
line_to( coord[2] );
line_to( coord[3] );
finish_to( coord[0] );
}
}
}