Rework on DXF export.
This commit is contained in:
parent
073a9e1724
commit
d54ade9403
|
@ -239,7 +239,7 @@ void EDA_3D_CANVAS::BuildBoard3DView()
|
|||
BOARD* pcb = GetBoard();
|
||||
bool realistic_mode = g_Parm_3D_Visu.IsRealisticMode();
|
||||
|
||||
// Number of segments to draw a circle using segments
|
||||
// Number of segments to convert a circle to polygon
|
||||
const int segcountforcircle = 16;
|
||||
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) );
|
||||
const int segcountLowQuality = 12; // segments to draw a circle with low quality
|
||||
|
|
|
@ -848,7 +848,7 @@ static void GRSClosedPoly( EDA_RECT* aClipBox, wxDC* aDC,
|
|||
// Close the polygon
|
||||
if( aPoints[lastpt] != aPoints[0] )
|
||||
{
|
||||
GRLineTo( aClipBox, aDC, aPoints[lastpt].x, aPoints[lastpt].y, aWidth, aColor );
|
||||
GRLineTo( aClipBox, aDC, aPoints[0].x, aPoints[0].y, aWidth, aColor );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <pcbnew.h>
|
||||
#include <wxPcbStruct.h>
|
||||
#include <trigo.h>
|
||||
#include <class_board.h>
|
||||
#include <class_pad.h>
|
||||
#include <class_track.h>
|
||||
#include <class_drawsegment.h>
|
||||
|
@ -38,6 +39,80 @@ static void addTextSegmToPoly( int x0, int y0, int xf, int yf )
|
|||
s_textCircle2SegmentCount, s_textWidth );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function ConvertBrdLayerToPolygonalContours
|
||||
* Build a set of polygons which are the outlines of copper items
|
||||
* (pads, tracks, texts, zones)
|
||||
* the holes in vias or pads are ignored
|
||||
* Usefull to export the shape of copper layers to dxf polygons
|
||||
* or 3D viewer
|
||||
* the polygons are not merged.
|
||||
* @param aLayer = A layer, like LAYER_N_BACK, etc.
|
||||
* @param aOutlines The CPOLYGONS_LIST to fill in with main outlines.
|
||||
* @return true if success, false if a contour is not valid
|
||||
*/
|
||||
void BOARD::ConvertBrdLayerToPolygonalContours( LAYER_NUM aLayer, CPOLYGONS_LIST& aOutlines )
|
||||
{
|
||||
// Number of segments to convert a circle to a polygon
|
||||
const int segcountforcircle = 16;
|
||||
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) );
|
||||
|
||||
// convert tracks and vias:
|
||||
for( TRACK* track = m_Track; track != NULL; track = track->Next() )
|
||||
{
|
||||
if( !track->IsOnLayer( aLayer ) )
|
||||
continue;
|
||||
|
||||
track->TransformShapeWithClearanceToPolygon( aOutlines,
|
||||
0, segcountforcircle, correctionFactor );
|
||||
}
|
||||
|
||||
// convert pads
|
||||
for( MODULE* module = m_Modules; module != NULL; module = module->Next() )
|
||||
{
|
||||
module->TransformPadsShapesWithClearanceToPolygon( aLayer,
|
||||
aOutlines, 0, segcountforcircle, correctionFactor );
|
||||
|
||||
// Micro-wave modules may have items on copper layers
|
||||
module->TransformGraphicShapesWithClearanceToPolygonSet( aLayer,
|
||||
aOutlines, 0, segcountforcircle, correctionFactor );
|
||||
}
|
||||
|
||||
// convert copper zones
|
||||
for( int ii = 0; ii < GetAreaCount(); ii++ )
|
||||
{
|
||||
ZONE_CONTAINER* zone = GetArea( ii );
|
||||
LAYER_NUM zonelayer = zone->GetLayer();
|
||||
|
||||
if( zonelayer == aLayer )
|
||||
zone->TransformSolidAreasShapesToPolygonSet(
|
||||
aOutlines, segcountforcircle, correctionFactor );
|
||||
}
|
||||
|
||||
// convert graphic items on copper layers (texts)
|
||||
for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
|
||||
{
|
||||
if( !item->IsOnLayer( aLayer ) )
|
||||
continue;
|
||||
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_LINE_T: // should not exist on copper layers
|
||||
( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
|
||||
aOutlines, 0, segcountforcircle, correctionFactor );
|
||||
break;
|
||||
|
||||
case PCB_TEXT_T:
|
||||
( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
|
||||
aOutlines, 0, segcountforcircle, correctionFactor );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* generate pads shapes on layer aLayer as polygons,
|
||||
* and adds these polygons to aCornerBuffer
|
||||
* aCornerBuffer = the buffer to store polygons
|
||||
|
@ -614,43 +689,26 @@ bool D_PAD::BuildPadDrillShapePolygon( CPOLYGONS_LIST& aCornerBuffer,
|
|||
int aInflateValue, int aSegmentsPerCircle ) const
|
||||
{
|
||||
wxSize drillsize = GetDrillSize();
|
||||
bool hasHole = drillsize.x && drillsize.y;
|
||||
|
||||
if( ! hasHole )
|
||||
if( !drillsize.x || !drillsize.y )
|
||||
return false;
|
||||
|
||||
drillsize.x += aInflateValue;
|
||||
drillsize.y += aInflateValue;
|
||||
|
||||
if( drillsize.x == drillsize.y ) // usual round hole
|
||||
{
|
||||
TransformCircleToPolygon( aCornerBuffer, GetPosition(),
|
||||
drillsize.x /2, aSegmentsPerCircle );
|
||||
(drillsize.x / 2) + aInflateValue, aSegmentsPerCircle );
|
||||
}
|
||||
else // Oblong hole
|
||||
{
|
||||
wxPoint ends_offset;
|
||||
wxPoint start, end;
|
||||
int width;
|
||||
|
||||
if( drillsize.x > drillsize.y ) // Horizontal oval
|
||||
{
|
||||
ends_offset.x = ( drillsize.x - drillsize.y ) / 2;
|
||||
width = drillsize.y;
|
||||
}
|
||||
else // Vertical oval
|
||||
{
|
||||
ends_offset.y = ( drillsize.y - drillsize.x ) / 2;
|
||||
width = drillsize.x;
|
||||
}
|
||||
GetOblongDrillGeometry( start, end, width );
|
||||
|
||||
RotatePoint( &ends_offset, GetOrientation() );
|
||||
width += aInflateValue * 2;
|
||||
|
||||
wxPoint start = GetPosition() + ends_offset;
|
||||
wxPoint end = GetPosition() - ends_offset;
|
||||
|
||||
// Prepare the shape creation
|
||||
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, start, end,
|
||||
aSegmentsPerCircle, width );
|
||||
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
|
||||
GetPosition() + start, GetPosition() + end, aSegmentsPerCircle, width );
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -685,6 +685,19 @@ public:
|
|||
CPOLYGONS_LIST& aHoles,
|
||||
wxString* aErrorText = NULL );
|
||||
|
||||
/**
|
||||
* Function ConvertBrdLayerToPolygonalContours
|
||||
* Build a set of polygons which are the outlines of copper items
|
||||
* (pads, tracks, vias, texts, zones)
|
||||
* Holes in vias or pads are ignored
|
||||
* Usefull to export the shape of copper layers to dxf polygons
|
||||
* or 3D viewer
|
||||
* the polygons are not merged.
|
||||
* @param aLayer = A copper layer, like LAYER_N_BACK, etc.
|
||||
* @param aOutlines The CPOLYGONS_LIST to fill in with items outline.
|
||||
*/
|
||||
void ConvertBrdLayerToPolygonalContours( LAYER_NUM aLayer, CPOLYGONS_LIST& aOutlines );
|
||||
|
||||
/**
|
||||
* Function GetLayerName
|
||||
* returns the name of a layer given by aLayer. Copper layers may
|
||||
|
|
|
@ -637,6 +637,39 @@ bool D_PAD::IsOnLayer( LAYER_NUM aLayer ) const
|
|||
}
|
||||
|
||||
|
||||
void D_PAD::GetOblongDrillGeometry( wxPoint& aStartPoint,
|
||||
wxPoint& aEndPoint, int& aWidth ) const
|
||||
{
|
||||
// calculates the start point, end point and width
|
||||
// of an equivalent segment which have the same position and width as the hole
|
||||
int delta_cx, delta_cy;
|
||||
|
||||
wxSize halfsize = GetDrillSize();;
|
||||
halfsize.x /= 2;
|
||||
halfsize.y /= 2;
|
||||
|
||||
if( m_Drill.x > m_Drill.y ) // horizontal
|
||||
{
|
||||
delta_cx = halfsize.x - halfsize.y;
|
||||
delta_cy = 0;
|
||||
aWidth = m_Drill.y;
|
||||
}
|
||||
else // vertical
|
||||
{
|
||||
delta_cx = 0;
|
||||
delta_cy = halfsize.y - halfsize.x;
|
||||
aWidth = m_Drill.x;
|
||||
}
|
||||
|
||||
RotatePoint( &delta_cx, &delta_cy, m_Orient );
|
||||
|
||||
aStartPoint.x = delta_cx;
|
||||
aStartPoint.y = delta_cy;
|
||||
|
||||
aEndPoint.x = - delta_cx;
|
||||
aEndPoint.y = - delta_cy;
|
||||
}
|
||||
|
||||
bool D_PAD::HitTest( const wxPoint& aPosition ) const
|
||||
{
|
||||
int dx, dy;
|
||||
|
|
|
@ -169,6 +169,17 @@ public:
|
|||
{ m_drillShape = aDrillShape; }
|
||||
PAD_DRILL_SHAPE_T GetDrillShape() const { return m_drillShape; }
|
||||
|
||||
/**
|
||||
* Function GetOblongDrillGeometry calculates the start point, end point and width
|
||||
* of an equivalent segment which have the same position and width as the hole
|
||||
* Usefull to plot/draw oblong holes like segments with rounded ends
|
||||
* used in draw and plot functions
|
||||
* @param aStartPoint = first point of the equivalent segment, relative to the pad position.
|
||||
* @param aEndPoint = second point of the equivalent segment, relative to the pad position.
|
||||
* @param aWidth = width equivalent segment.
|
||||
*/
|
||||
void GetOblongDrillGeometry( wxPoint& aStartPoint, wxPoint& aEndPoint, int& aWidth ) const;
|
||||
|
||||
void SetLayerMask( LAYER_MSK aLayerMask ) { m_layerMask = aLayerMask; }
|
||||
LAYER_MSK GetLayerMask() const { return m_layerMask; }
|
||||
|
||||
|
|
|
@ -310,7 +310,6 @@ void D_PAD::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDraw_mode,
|
|||
void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
|
||||
{
|
||||
wxPoint coord[4];
|
||||
int delta_cx, delta_cy;
|
||||
double angle = m_Orient;
|
||||
int seg_width;
|
||||
|
||||
|
@ -439,27 +438,12 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
|
|||
break;
|
||||
|
||||
case PAD_DRILL_OBLONG:
|
||||
halfsize.x = m_Drill.x >> 1;
|
||||
halfsize.y = m_Drill.y >> 1;
|
||||
|
||||
if( m_Drill.x > m_Drill.y ) // horizontal
|
||||
{
|
||||
delta_cx = halfsize.x - halfsize.y;
|
||||
delta_cy = 0;
|
||||
seg_width = m_Drill.y;
|
||||
wxPoint drl_start, drl_end;
|
||||
GetOblongDrillGeometry( drl_start, drl_end, seg_width );
|
||||
GRFilledSegment( aClipBox, aDC, holepos + drl_start,
|
||||
holepos + drl_end, seg_width, hole_color );
|
||||
}
|
||||
else // vertical
|
||||
{
|
||||
delta_cx = 0;
|
||||
delta_cy = halfsize.y - halfsize.x;
|
||||
seg_width = m_Drill.x;
|
||||
}
|
||||
|
||||
RotatePoint( &delta_cx, &delta_cy, angle );
|
||||
|
||||
GRFillCSegm( aClipBox, aDC, holepos.x + delta_cx, holepos.y + delta_cy,
|
||||
holepos.x - delta_cx, holepos.y - delta_cy, seg_width,
|
||||
hole_color );
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -204,6 +204,17 @@ void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, LAYER_NUM aLayer,
|
|||
void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LAYER_MSK aLayerMask,
|
||||
const PCB_PLOT_PARAMS& aPlotOpt );
|
||||
|
||||
/**
|
||||
* Function PlotLayerOutlines
|
||||
* plot copper outline of a copper layer.
|
||||
* @param aBoard = the board to plot
|
||||
* @param aPlotter = the plotter to use
|
||||
* @param aLayerMask = the mask to define the layers to plot
|
||||
* @param aPlotOpt = the plot options. Has meaning for some formats only
|
||||
*/
|
||||
void PlotLayerOutlines( BOARD *aBoard, PLOTTER* aPlotter,
|
||||
LAYER_MSK aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt );
|
||||
|
||||
/**
|
||||
* Function PlotSilkScreen
|
||||
* plot silkscreen layers which have specific requirements, mainly for pads.
|
||||
|
|
|
@ -176,10 +176,18 @@ void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, LAYER_NUM aLayer,
|
|||
case LAYER_N_15:
|
||||
case LAST_COPPER_LAYER:
|
||||
// Skip NPTH pads on copper layers ( only if hole size == pad size ):
|
||||
plotOpt.SetSkipPlotNPTH_Pads( true );
|
||||
// Drill mark will be plotted,
|
||||
// if drill mark is SMALL_DRILL_SHAPE or FULL_DRILL_SHAPE
|
||||
if( plotOpt.GetFormat() == PLOT_FORMAT_DXF )
|
||||
{
|
||||
plotOpt.SetSkipPlotNPTH_Pads( false );
|
||||
PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
|
||||
}
|
||||
else
|
||||
{
|
||||
plotOpt.SetSkipPlotNPTH_Pads( true );
|
||||
PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
||||
}
|
||||
break;
|
||||
|
||||
case SOLDERMASK_N_BACK:
|
||||
|
@ -190,7 +198,12 @@ void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, LAYER_NUM aLayer,
|
|||
|
||||
// Plot solder mask:
|
||||
if( soldermask_min_thickness == 0 )
|
||||
{
|
||||
if( plotOpt.GetFormat() == PLOT_FORMAT_DXF )
|
||||
PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
|
||||
else
|
||||
PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
||||
}
|
||||
else
|
||||
PlotSolderMaskLayer( aBoard, aPlotter, layer_mask, plotOpt,
|
||||
soldermask_min_thickness );
|
||||
|
@ -202,11 +215,18 @@ void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, LAYER_NUM aLayer,
|
|||
plotOpt.SetSkipPlotNPTH_Pads( false );
|
||||
// Disable plot pad holes
|
||||
plotOpt.SetDrillMarksType( PCB_PLOT_PARAMS::NO_DRILL_SHAPE );
|
||||
|
||||
if( plotOpt.GetFormat() == PLOT_FORMAT_DXF )
|
||||
PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
|
||||
else
|
||||
PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
||||
break;
|
||||
|
||||
case SILKSCREEN_N_FRONT:
|
||||
case SILKSCREEN_N_BACK:
|
||||
if( plotOpt.GetFormat() == PLOT_FORMAT_DXF )
|
||||
PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
|
||||
else
|
||||
PlotSilkScreen( aBoard, aPlotter, layer_mask, plotOpt );
|
||||
|
||||
// Gerber: Subtract soldermask from silkscreen if enabled
|
||||
|
@ -444,6 +464,115 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter,
|
|||
itemplotter.PlotDrillMarks();
|
||||
}
|
||||
|
||||
/* Plot outlines of copper, for copper layer
|
||||
*/
|
||||
#include "clipper.hpp"
|
||||
void PlotLayerOutlines( BOARD *aBoard, PLOTTER* aPlotter,
|
||||
LAYER_MSK aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt )
|
||||
{
|
||||
|
||||
BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
|
||||
itemplotter.SetLayerMask( aLayerMask );
|
||||
|
||||
CPOLYGONS_LIST outlines;
|
||||
|
||||
for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; layer++ )
|
||||
{
|
||||
LAYER_MSK layer_mask = GetLayerMask( layer );
|
||||
|
||||
if( (aLayerMask & layer_mask ) == 0 )
|
||||
continue;
|
||||
|
||||
outlines.RemoveAllContours();
|
||||
aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines );
|
||||
|
||||
// Merge all overlapping polygons.
|
||||
KI_POLYGON_SET kpolygons;
|
||||
KI_POLYGON_SET ktmp;
|
||||
outlines.ExportTo( ktmp );
|
||||
|
||||
kpolygons += ktmp;
|
||||
|
||||
// Plot outlines
|
||||
std::vector< wxPoint > cornerList;
|
||||
|
||||
for( unsigned ii = 0; ii < kpolygons.size(); ii++ )
|
||||
{
|
||||
KI_POLYGON polygon = kpolygons[ii];
|
||||
|
||||
// polygon contains only one polygon, but it can have holes linked by
|
||||
// overlapping segments.
|
||||
// To plot clean outlines, we have to break this polygon into more polygons with
|
||||
// no overlapping segments, using Clipper, because boost::polygon
|
||||
// does not allow that
|
||||
ClipperLib::Path raw_polygon;
|
||||
ClipperLib::Paths normalized_polygons;
|
||||
|
||||
for( unsigned ic = 0; ic < polygon.size(); ic++ )
|
||||
{
|
||||
KI_POLY_POINT corner = *(polygon.begin() + ic);
|
||||
raw_polygon.push_back( ClipperLib::IntPoint( corner.x(), corner.y() ) );
|
||||
}
|
||||
|
||||
ClipperLib::SimplifyPolygon( raw_polygon, normalized_polygons );
|
||||
|
||||
// Now we have one or more basic polygons: plot each polygon
|
||||
for( unsigned ii = 0; ii < normalized_polygons.size(); ii++ )
|
||||
{
|
||||
ClipperLib::Path& polygon = normalized_polygons[ii];
|
||||
cornerList.clear();
|
||||
|
||||
for( unsigned jj = 0; jj < polygon.size(); jj++ )
|
||||
cornerList.push_back( wxPoint( polygon[jj].X , polygon[jj].Y ) );
|
||||
|
||||
// Ensure the polygon is closed
|
||||
if( cornerList[0] != cornerList[cornerList.size()-1] )
|
||||
cornerList.push_back( cornerList[0] );
|
||||
|
||||
aPlotter->PlotPoly( cornerList, NO_FILL );
|
||||
}
|
||||
}
|
||||
|
||||
// Plot pad holes
|
||||
if( aPlotOpt.GetDrillMarksType() != PCB_PLOT_PARAMS::NO_DRILL_SHAPE )
|
||||
{
|
||||
for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
|
||||
{
|
||||
for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() )
|
||||
{
|
||||
wxSize hole = pad->GetDrillSize();
|
||||
|
||||
if( hole.x == 0 || hole.y == 0 )
|
||||
continue;
|
||||
|
||||
if( hole.x == hole.y )
|
||||
aPlotter->Circle( pad->GetPosition(), hole.x, NO_FILL );
|
||||
else
|
||||
{
|
||||
wxPoint drl_start, drl_end;
|
||||
int width;
|
||||
pad->GetOblongDrillGeometry( drl_start, drl_end, width );
|
||||
aPlotter->ThickSegment( pad->GetPosition() + drl_start,
|
||||
pad->GetPosition() + drl_end, width, SKETCH );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Plot vias holes
|
||||
for( TRACK* track = aBoard->m_Track; track; track = track->Next() )
|
||||
{
|
||||
const VIA* via = dynamic_cast<const VIA*>( track );
|
||||
|
||||
if( via && via->IsOnLayer( layer ) ) // via holes can be not through holes
|
||||
{
|
||||
aPlotter->Circle( via->GetPosition(), via->GetDrillValue(), NO_FILL );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Plot a solder mask layer.
|
||||
* Solder mask layers have a minimum thickness value and cannot be drawn like standard layers,
|
||||
* unless the minimum thickness is 0.
|
||||
|
|
Loading…
Reference in New Issue