2012-09-24 16:03:03 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2022-01-13 13:45:48 +00:00
|
|
|
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
2012-09-24 16:03:03 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
2020-01-07 17:12:59 +00:00
|
|
|
#include <algorithm> // for min
|
|
|
|
#include <bitset> // for bitset, operator&, __bi...
|
|
|
|
#include <math.h> // for abs
|
|
|
|
#include <stddef.h> // for NULL, size_t
|
|
|
|
|
|
|
|
#include <geometry/seg.h> // for SEG
|
2020-09-12 20:09:40 +00:00
|
|
|
#include <geometry/shape_circle.h>
|
2020-01-07 17:12:59 +00:00
|
|
|
#include <geometry/shape_line_chain.h> // for SHAPE_LINE_CHAIN
|
|
|
|
#include <geometry/shape_poly_set.h> // for SHAPE_POLY_SET, SHAPE_P...
|
2020-09-12 20:09:40 +00:00
|
|
|
#include <geometry/shape_segment.h>
|
2021-07-29 09:56:22 +00:00
|
|
|
#include <string_utils.h>
|
2021-03-20 15:35:37 +00:00
|
|
|
#include <macros.h>
|
2020-01-07 17:12:59 +00:00
|
|
|
#include <math/util.h> // for KiROUND, Clamp
|
|
|
|
#include <math/vector2d.h> // for VECTOR2I
|
2021-08-18 20:38:14 +00:00
|
|
|
#include <plotters/plotter_gerber.h>
|
2012-09-24 16:03:03 +00:00
|
|
|
#include <trigo.h>
|
2020-01-07 17:12:59 +00:00
|
|
|
|
|
|
|
#include <board_design_settings.h> // for BOARD_DESIGN_SETTINGS
|
|
|
|
#include <core/typeinfo.h> // for dyn_cast, PCB_DIMENSION_T
|
|
|
|
#include <gbr_metadata.h>
|
|
|
|
#include <gbr_netlist_metadata.h> // for GBR_NETLIST_METADATA
|
2021-08-17 19:41:08 +00:00
|
|
|
#include <layer_ids.h> // for LSET, IsCopperLayer
|
2021-05-01 14:46:50 +00:00
|
|
|
#include <pad_shapes.h> // for PAD_ATTRIB::NPTH
|
2020-01-07 17:12:59 +00:00
|
|
|
#include <pcbplot.h>
|
|
|
|
#include <pcb_plot_params.h> // for PCB_PLOT_PARAMS, PCB_PL...
|
2021-01-04 22:26:23 +00:00
|
|
|
#include <advanced_config.h>
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2020-11-12 20:19:22 +00:00
|
|
|
#include <board.h>
|
2020-11-14 18:11:28 +00:00
|
|
|
#include <board_item.h> // for BOARD_ITEM, S_CIRCLE
|
2021-06-11 16:59:28 +00:00
|
|
|
#include <pcb_dimension.h>
|
2020-10-04 23:34:59 +00:00
|
|
|
#include <pcb_shape.h>
|
|
|
|
#include <fp_shape.h>
|
2020-11-12 20:19:22 +00:00
|
|
|
#include <footprint.h>
|
2020-11-12 22:30:02 +00:00
|
|
|
#include <fp_text.h>
|
2022-01-30 10:52:52 +00:00
|
|
|
#include <fp_textbox.h>
|
2021-06-11 21:07:02 +00:00
|
|
|
#include <pcb_track.h>
|
2020-11-12 22:30:02 +00:00
|
|
|
#include <pad.h>
|
2020-11-11 23:05:59 +00:00
|
|
|
#include <pcb_target.h>
|
2020-10-04 23:34:59 +00:00
|
|
|
#include <pcb_text.h>
|
2022-01-30 10:52:52 +00:00
|
|
|
#include <pcb_textbox.h>
|
2020-11-11 23:05:59 +00:00
|
|
|
#include <zone.h>
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2020-01-07 17:12:59 +00:00
|
|
|
#include <wx/debug.h> // for wxASSERT_MSG
|
|
|
|
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-07-21 23:14:56 +00:00
|
|
|
COLOR4D BRDITEMS_PLOTTER::getColor( int aLayer ) const
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2020-03-30 01:43:18 +00:00
|
|
|
COLOR4D color = ColorSettings()->GetColor( aLayer );
|
2017-10-08 14:08:42 +00:00
|
|
|
|
2020-03-25 15:16:47 +00:00
|
|
|
// A hack to avoid plotting a white item in white color, expecting the paper
|
2017-10-08 14:08:42 +00:00
|
|
|
// is also white: use a non white color:
|
2017-02-20 17:48:27 +00:00
|
|
|
if( color == COLOR4D::WHITE )
|
2017-02-20 16:57:41 +00:00
|
|
|
color = COLOR4D( LIGHTGRAY );
|
2017-10-08 14:08:42 +00:00
|
|
|
|
2012-09-24 16:03:03 +00:00
|
|
|
return color;
|
|
|
|
}
|
|
|
|
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2021-07-26 17:28:37 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotPad( const PAD* aPad, const COLOR4D& aColor, OUTLINE_MODE aPlotMode )
|
2012-09-25 07:49:29 +00:00
|
|
|
{
|
2022-01-01 06:04:08 +00:00
|
|
|
VECTOR2I shape_pos = aPad->ShapePos();
|
2016-09-19 11:01:36 +00:00
|
|
|
GBR_METADATA gbr_metadata;
|
|
|
|
|
2020-06-14 16:16:01 +00:00
|
|
|
bool plotOnCopperLayer = ( m_layerMask & LSET::AllCuMask() ).any();
|
|
|
|
bool plotOnExternalCopperLayer = ( m_layerMask & LSET::ExternalCuMask() ).any();
|
|
|
|
|
|
|
|
// Pad not on the solder mask layer cannot be soldered.
|
|
|
|
// therefore it can have a specific aperture attribute.
|
|
|
|
// Not yet in use.
|
|
|
|
// bool isPadOnBoardTechLayers = ( aPad->GetLayerSet() & LSET::AllBoardTechMask() ).any();
|
2016-09-19 11:01:36 +00:00
|
|
|
|
|
|
|
gbr_metadata.SetCmpReference( aPad->GetParent()->GetReference() );
|
|
|
|
|
2020-06-14 16:16:01 +00:00
|
|
|
if( plotOnCopperLayer )
|
2016-09-19 11:01:36 +00:00
|
|
|
{
|
|
|
|
gbr_metadata.SetNetAttribType( GBR_NETINFO_ALL );
|
2017-05-03 18:04:31 +00:00
|
|
|
gbr_metadata.SetCopper( true );
|
2021-07-19 23:56:05 +00:00
|
|
|
|
2020-06-14 16:16:01 +00:00
|
|
|
// Gives a default attribute, for instance for pads used as tracks in net ties:
|
|
|
|
// Connector pads and SMD pads are on external layers
|
|
|
|
// if on internal layers, they are certainly used as net tie
|
|
|
|
// and are similar to tracks: just conductor items
|
|
|
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR );
|
2016-09-19 11:01:36 +00:00
|
|
|
|
2020-06-14 16:16:01 +00:00
|
|
|
const bool useUTF8 = false;
|
|
|
|
const bool useQuoting = false;
|
2021-08-23 23:10:21 +00:00
|
|
|
gbr_metadata.SetPadName( aPad->GetNumber(), useUTF8, useQuoting );
|
2019-11-17 09:11:29 +00:00
|
|
|
|
2021-08-23 23:10:21 +00:00
|
|
|
if( !aPad->GetNumber().IsEmpty() )
|
2020-06-14 16:16:01 +00:00
|
|
|
gbr_metadata.SetPadPinFunction( aPad->GetPinFunction(), useUTF8, useQuoting );
|
2016-09-19 11:01:36 +00:00
|
|
|
|
|
|
|
gbr_metadata.SetNetName( aPad->GetNetname() );
|
|
|
|
|
|
|
|
// Some pads are mechanical pads ( through hole or smd )
|
|
|
|
// when this is the case, they have no pad name and/or are not plated.
|
|
|
|
// In this case gerber files have slightly different attributes.
|
2021-08-23 23:10:21 +00:00
|
|
|
if( aPad->GetAttribute() == PAD_ATTRIB::NPTH || aPad->GetNumber().IsEmpty() )
|
2016-09-19 11:01:36 +00:00
|
|
|
gbr_metadata.m_NetlistMetadata.m_NotInNet = true;
|
|
|
|
|
2020-06-14 16:16:01 +00:00
|
|
|
if( !plotOnExternalCopperLayer )
|
2016-09-19 11:01:36 +00:00
|
|
|
{
|
2020-06-14 16:16:01 +00:00
|
|
|
// the .P object attribute (GBR_NETLIST_METADATA::GBR_NETINFO_PAD)
|
|
|
|
// is used on outer layers, unless the component is embedded
|
|
|
|
// or a "etched" component (fp only drawn, not a physical component)
|
|
|
|
// Currently, Pcbnew does not handle embedded component, so we disable the .P
|
|
|
|
// attribute on internal layers
|
|
|
|
// Note the Gerber doc is not really clear about through holes pads about the .P
|
2016-09-19 11:01:36 +00:00
|
|
|
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_NET |
|
|
|
|
GBR_NETLIST_METADATA::GBR_NETINFO_CMP );
|
|
|
|
|
|
|
|
}
|
2020-06-14 16:16:01 +00:00
|
|
|
|
|
|
|
// Some attributes are reserved to the external copper layers:
|
|
|
|
// GBR_APERTURE_ATTRIB_CONNECTORPAD and GBR_APERTURE_ATTRIB_SMDPAD_CUDEF
|
|
|
|
// for instance.
|
2021-05-01 14:46:50 +00:00
|
|
|
// Pad with type PAD_ATTRIB::CONN or PAD_ATTRIB::SMD that is not on outer layer
|
2020-06-14 16:16:01 +00:00
|
|
|
// has its aperture attribute set to GBR_APERTURE_ATTRIB_CONDUCTOR
|
|
|
|
switch( aPad->GetAttribute() )
|
2016-09-19 11:01:36 +00:00
|
|
|
{
|
2021-05-01 14:46:50 +00:00
|
|
|
case PAD_ATTRIB::NPTH: // Mechanical pad through hole
|
2020-06-14 16:16:01 +00:00
|
|
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_WASHERPAD );
|
|
|
|
break;
|
2016-09-19 11:01:36 +00:00
|
|
|
|
2021-05-01 14:46:50 +00:00
|
|
|
case PAD_ATTRIB::PTH : // Pad through hole, a hole is also expected
|
2021-08-17 19:41:08 +00:00
|
|
|
gbr_metadata.SetApertureAttrib(
|
|
|
|
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_COMPONENTPAD );
|
2020-06-14 16:16:01 +00:00
|
|
|
break;
|
2016-09-19 11:01:36 +00:00
|
|
|
|
2021-05-01 14:46:50 +00:00
|
|
|
case PAD_ATTRIB::CONN: // Connector pads, no solder paste but with solder mask.
|
2020-06-14 16:16:01 +00:00
|
|
|
if( plotOnExternalCopperLayer )
|
2021-08-17 19:41:08 +00:00
|
|
|
gbr_metadata.SetApertureAttrib(
|
|
|
|
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONNECTORPAD );
|
2020-06-14 16:16:01 +00:00
|
|
|
break;
|
2016-09-19 11:01:36 +00:00
|
|
|
|
2021-05-01 14:46:50 +00:00
|
|
|
case PAD_ATTRIB::SMD: // SMD pads (on external copper layer only)
|
2021-07-19 23:56:05 +00:00
|
|
|
// with solder paste and mask
|
2020-06-14 16:16:01 +00:00
|
|
|
if( plotOnExternalCopperLayer )
|
2021-08-17 19:41:08 +00:00
|
|
|
gbr_metadata.SetApertureAttrib(
|
|
|
|
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_SMDPAD_CUDEF );
|
2020-06-14 16:16:01 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-12-11 10:36:45 +00:00
|
|
|
|
2020-06-14 16:16:01 +00:00
|
|
|
// Fabrication properties can have specific GBR_APERTURE_METADATA options
|
|
|
|
// that replace previous aperture attribute:
|
|
|
|
switch( aPad->GetProperty() )
|
|
|
|
{
|
2021-05-01 14:58:30 +00:00
|
|
|
case PAD_PROP::BGA: // Only applicable to outer layers
|
2020-06-14 16:16:01 +00:00
|
|
|
if( plotOnExternalCopperLayer )
|
2021-08-17 19:41:08 +00:00
|
|
|
gbr_metadata.SetApertureAttrib(
|
|
|
|
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_BGAPAD_CUDEF );
|
2020-06-14 16:16:01 +00:00
|
|
|
break;
|
2019-12-11 10:36:45 +00:00
|
|
|
|
2021-05-01 14:58:30 +00:00
|
|
|
case PAD_PROP::FIDUCIAL_GLBL:
|
2021-08-17 19:41:08 +00:00
|
|
|
gbr_metadata.SetApertureAttrib(
|
|
|
|
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_FIDUCIAL_GLBL );
|
2020-06-14 16:16:01 +00:00
|
|
|
break;
|
2019-12-11 10:36:45 +00:00
|
|
|
|
2021-05-01 14:58:30 +00:00
|
|
|
case PAD_PROP::FIDUCIAL_LOCAL:
|
2021-08-17 19:41:08 +00:00
|
|
|
gbr_metadata.SetApertureAttrib(
|
|
|
|
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_FIDUCIAL_LOCAL );
|
2020-06-14 16:16:01 +00:00
|
|
|
break;
|
2019-12-11 10:36:45 +00:00
|
|
|
|
2021-05-01 14:58:30 +00:00
|
|
|
case PAD_PROP::TESTPOINT: // Only applicable to outer layers
|
2020-06-14 16:16:01 +00:00
|
|
|
if( plotOnExternalCopperLayer )
|
2021-08-17 19:41:08 +00:00
|
|
|
gbr_metadata.SetApertureAttrib(
|
|
|
|
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_TESTPOINT );
|
2020-06-14 16:16:01 +00:00
|
|
|
break;
|
2019-12-11 10:36:45 +00:00
|
|
|
|
2021-05-01 14:58:30 +00:00
|
|
|
case PAD_PROP::HEATSINK:
|
2021-08-17 19:41:08 +00:00
|
|
|
gbr_metadata.SetApertureAttrib(
|
|
|
|
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_HEATSINKPAD );
|
2020-06-14 16:16:01 +00:00
|
|
|
break;
|
2019-12-11 10:36:45 +00:00
|
|
|
|
2021-05-01 14:58:30 +00:00
|
|
|
case PAD_PROP::CASTELLATED:
|
2021-08-17 19:41:08 +00:00
|
|
|
gbr_metadata.SetApertureAttrib(
|
|
|
|
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CASTELLATEDPAD );
|
2020-06-14 16:16:01 +00:00
|
|
|
break;
|
2019-12-11 10:36:45 +00:00
|
|
|
|
2021-05-01 14:58:30 +00:00
|
|
|
case PAD_PROP::NONE:
|
2020-06-14 16:16:01 +00:00
|
|
|
break;
|
2016-09-19 11:01:36 +00:00
|
|
|
}
|
|
|
|
|
2020-06-14 16:16:01 +00:00
|
|
|
// Ensure NPTH pads have *always* the GBR_APERTURE_ATTRIB_WASHERPAD attribute
|
2021-05-01 14:46:50 +00:00
|
|
|
if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
|
2016-09-19 11:01:36 +00:00
|
|
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_WASHERPAD );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_CMP );
|
|
|
|
}
|
2012-09-25 07:49:29 +00:00
|
|
|
|
|
|
|
// Set plot color (change WHITE to LIGHTGRAY because
|
|
|
|
// the white items are not seen on a white paper or screen
|
|
|
|
m_plotter->SetColor( aColor != WHITE ? aColor : LIGHTGRAY);
|
|
|
|
|
2020-05-01 16:24:01 +00:00
|
|
|
if( aPlotMode == SKETCH )
|
|
|
|
m_plotter->SetCurrentLineWidth( GetSketchPadLineWidth(), &gbr_metadata );
|
|
|
|
|
2012-09-25 07:49:29 +00:00
|
|
|
switch( aPad->GetShape() )
|
|
|
|
{
|
2021-05-01 12:22:35 +00:00
|
|
|
case PAD_SHAPE::CIRCLE:
|
2016-09-19 11:01:36 +00:00
|
|
|
m_plotter->FlashPadCircle( shape_pos, aPad->GetSize().x, aPlotMode, &gbr_metadata );
|
2012-09-25 07:49:29 +00:00
|
|
|
break;
|
|
|
|
|
2021-05-01 12:22:35 +00:00
|
|
|
case PAD_SHAPE::OVAL:
|
2022-01-16 01:06:25 +00:00
|
|
|
m_plotter->FlashPadOval( shape_pos, aPad->GetSize(), aPad->GetOrientation(), aPlotMode,
|
2021-01-03 13:59:23 +00:00
|
|
|
&gbr_metadata );
|
2012-09-25 07:49:29 +00:00
|
|
|
break;
|
|
|
|
|
2021-05-01 12:22:35 +00:00
|
|
|
case PAD_SHAPE::RECT:
|
2022-01-16 01:06:25 +00:00
|
|
|
m_plotter->FlashPadRect( shape_pos, aPad->GetSize(), aPad->GetOrientation(), aPlotMode,
|
2020-06-22 19:35:09 +00:00
|
|
|
&gbr_metadata );
|
2012-09-25 07:49:29 +00:00
|
|
|
break;
|
|
|
|
|
2021-05-01 12:22:35 +00:00
|
|
|
case PAD_SHAPE::ROUNDRECT:
|
2016-04-06 18:15:49 +00:00
|
|
|
m_plotter->FlashPadRoundRect( shape_pos, aPad->GetSize(), aPad->GetRoundRectCornerRadius(),
|
2022-01-16 01:06:25 +00:00
|
|
|
aPad->GetOrientation(), aPlotMode, &gbr_metadata );
|
2016-04-06 18:15:49 +00:00
|
|
|
break;
|
|
|
|
|
2021-05-01 12:22:35 +00:00
|
|
|
case PAD_SHAPE::TRAPEZOID:
|
2020-09-28 13:36:52 +00:00
|
|
|
{
|
|
|
|
// Build the pad polygon in coordinates relative to the pad
|
|
|
|
// (i.e. for a pad at pos 0,0, rot 0.0). Needed to use aperture macros,
|
|
|
|
// to be able to create a pattern common to all trapezoid pads having the same shape
|
2021-12-29 19:02:50 +00:00
|
|
|
VECTOR2I coord[4];
|
2021-08-17 19:41:08 +00:00
|
|
|
|
|
|
|
// Order is lower left, lower right, upper right, upper left.
|
2021-12-29 19:02:50 +00:00
|
|
|
VECTOR2I half_size = aPad->GetSize() / 2;
|
|
|
|
VECTOR2I trap_delta = aPad->GetDelta() / 2;
|
2020-09-28 13:36:52 +00:00
|
|
|
|
2021-12-29 19:02:50 +00:00
|
|
|
coord[0] = VECTOR2I( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
|
|
|
|
coord[1] = VECTOR2I( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
|
|
|
|
coord[2] = VECTOR2I( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
|
|
|
|
coord[3] = VECTOR2I( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
|
2020-09-28 13:36:52 +00:00
|
|
|
|
2022-01-16 01:06:25 +00:00
|
|
|
m_plotter->FlashPadTrapez( shape_pos, coord, aPad->GetOrientation(), aPlotMode,
|
|
|
|
&gbr_metadata );
|
2020-09-28 13:36:52 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2021-05-01 12:22:35 +00:00
|
|
|
case PAD_SHAPE::CHAMFERED_RECT:
|
2020-10-08 12:51:25 +00:00
|
|
|
if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
|
|
|
|
{
|
2022-01-16 01:06:25 +00:00
|
|
|
GERBER_PLOTTER* gerberPlotter = static_cast<GERBER_PLOTTER*>( m_plotter );
|
|
|
|
|
|
|
|
gerberPlotter->FlashPadChamferRoundRect( shape_pos, aPad->GetSize(),
|
|
|
|
aPad->GetRoundRectCornerRadius(),
|
|
|
|
aPad->GetChamferRectRatio(),
|
|
|
|
aPad->GetChamferPositions(),
|
|
|
|
aPad->GetOrientation(), aPlotMode,
|
|
|
|
&gbr_metadata );
|
2020-10-08 12:51:25 +00:00
|
|
|
break;
|
|
|
|
}
|
2021-08-17 19:41:08 +00:00
|
|
|
|
2020-10-08 12:51:25 +00:00
|
|
|
KI_FALLTHROUGH;
|
|
|
|
|
|
|
|
default:
|
2021-05-01 12:22:35 +00:00
|
|
|
case PAD_SHAPE::CUSTOM:
|
2020-06-22 19:35:09 +00:00
|
|
|
{
|
2020-07-25 11:58:17 +00:00
|
|
|
const std::shared_ptr<SHAPE_POLY_SET>& polygons = aPad->GetEffectivePolygon();
|
2017-01-13 17:51:22 +00:00
|
|
|
|
2020-07-25 11:58:17 +00:00
|
|
|
if( polygons->OutlineCount() )
|
|
|
|
{
|
2022-01-16 01:06:25 +00:00
|
|
|
m_plotter->FlashPadCustom( shape_pos, aPad->GetSize(), aPad->GetOrientation(),
|
|
|
|
polygons.get(), aPlotMode, &gbr_metadata );
|
2020-07-25 11:58:17 +00:00
|
|
|
}
|
2020-06-22 19:35:09 +00:00
|
|
|
}
|
2012-09-25 07:49:29 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotFootprintTextItems( const FOOTPRINT* aFootprint )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-03-06 09:27:41 +00:00
|
|
|
const FP_TEXT* textItem = &aFootprint->Reference();
|
2021-07-21 23:14:56 +00:00
|
|
|
int textLayer = textItem->GetLayer();
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-06-09 19:32:58 +00:00
|
|
|
// Reference and value are specific items, not in graphic items list
|
2018-05-30 19:45:02 +00:00
|
|
|
if( GetPlotReference() && m_layerMask[textLayer]
|
2020-10-04 23:34:59 +00:00
|
|
|
&& ( textItem->IsVisible() || GetPlotInvisibleText() ) )
|
2018-05-30 19:45:02 +00:00
|
|
|
{
|
2020-11-24 22:16:41 +00:00
|
|
|
PlotFootprintTextItem( textItem, getColor( textLayer ) );
|
2018-05-30 19:45:02 +00:00
|
|
|
}
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
textItem = &aFootprint->Value();
|
2020-10-04 23:34:59 +00:00
|
|
|
textLayer = textItem->GetLayer();
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2018-05-30 19:45:02 +00:00
|
|
|
if( GetPlotValue() && m_layerMask[textLayer]
|
2020-10-04 23:34:59 +00:00
|
|
|
&& ( textItem->IsVisible() || GetPlotInvisibleText() ) )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2020-11-24 22:16:41 +00:00
|
|
|
PlotFootprintTextItem( textItem, getColor( textLayer ) );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
for( const BOARD_ITEM* item : aFootprint->GraphicalItems() )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-03-06 09:27:41 +00:00
|
|
|
textItem = dyn_cast<const FP_TEXT*>( item );
|
2014-06-06 09:44:21 +00:00
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
if( !textItem )
|
2012-09-24 16:03:03 +00:00
|
|
|
continue;
|
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
if( !textItem->IsVisible() )
|
2012-09-24 16:03:03 +00:00
|
|
|
continue;
|
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
textLayer = textItem->GetLayer();
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2020-10-13 17:46:48 +00:00
|
|
|
if( textLayer == Edge_Cuts || textLayer >= PCB_LAYER_ID_COUNT )
|
|
|
|
continue;
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-12-05 21:56:55 +00:00
|
|
|
if( !m_layerMask[textLayer] || aFootprint->GetPrivateLayers().test( textLayer ) )
|
2012-09-24 16:03:03 +00:00
|
|
|
continue;
|
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
if( textItem->GetText() == wxT( "${REFERENCE}" ) && !GetPlotReference() )
|
2018-02-10 20:47:19 +00:00
|
|
|
continue;
|
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
if( textItem->GetText() == wxT( "${VALUE}" ) && !GetPlotValue() )
|
2018-02-10 20:47:19 +00:00
|
|
|
continue;
|
|
|
|
|
2020-11-24 22:16:41 +00:00
|
|
|
PlotFootprintTextItem( textItem, getColor( textLayer ) );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-08-23 10:25:02 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotPcbGraphicItem( const BOARD_ITEM* item )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-08-23 10:25:02 +00:00
|
|
|
switch( item->Type() )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-08-23 10:25:02 +00:00
|
|
|
case PCB_SHAPE_T:
|
|
|
|
PlotPcbShape( static_cast<const PCB_SHAPE*>( item ) );
|
|
|
|
break;
|
2020-10-13 17:46:48 +00:00
|
|
|
|
2021-08-23 10:25:02 +00:00
|
|
|
case PCB_TEXT_T:
|
2022-01-30 10:52:52 +00:00
|
|
|
PlotPcbText( static_cast<const PCB_TEXT*>( item ), item->GetLayer() );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PCB_TEXTBOX_T:
|
|
|
|
PlotPcbText( static_cast<const PCB_TEXTBOX*>( item ), item->GetLayer() );
|
|
|
|
PlotPcbShape( static_cast<const PCB_TEXTBOX*>( item ) );
|
2021-08-23 10:25:02 +00:00
|
|
|
break;
|
2020-09-12 20:09:40 +00:00
|
|
|
|
2021-08-23 10:25:02 +00:00
|
|
|
case PCB_DIM_ALIGNED_T:
|
|
|
|
case PCB_DIM_CENTER_T:
|
|
|
|
case PCB_DIM_RADIAL_T:
|
|
|
|
case PCB_DIM_ORTHOGONAL_T:
|
|
|
|
case PCB_DIM_LEADER_T:
|
|
|
|
PlotDimension( static_cast<const PCB_DIMENSION_BASE*>( item ) );
|
|
|
|
break;
|
2020-10-13 17:46:48 +00:00
|
|
|
|
2021-08-23 10:25:02 +00:00
|
|
|
case PCB_TARGET_T:
|
|
|
|
PlotPcbTarget( static_cast<const PCB_TARGET*>( item ) );
|
|
|
|
break;
|
2020-09-12 20:09:40 +00:00
|
|
|
|
2021-08-23 10:25:02 +00:00
|
|
|
default:
|
|
|
|
break;
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-17 19:41:08 +00:00
|
|
|
|
2021-08-23 10:25:02 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotBoardGraphicItems()
|
|
|
|
{
|
|
|
|
for( const BOARD_ITEM* item : m_board->Drawings() )
|
|
|
|
PlotPcbGraphicItem( item );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-29 17:31:40 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotFootprintTextItem( const FP_TEXT* aText, const COLOR4D& aColor )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-07-26 17:28:37 +00:00
|
|
|
COLOR4D color = aColor;
|
|
|
|
|
2017-02-20 17:48:27 +00:00
|
|
|
if( aColor == COLOR4D::WHITE )
|
2021-07-26 17:28:37 +00:00
|
|
|
color = COLOR4D( LIGHTGRAY );
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2021-07-26 17:28:37 +00:00
|
|
|
m_plotter->SetColor( color );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
|
|
|
// calculate some text parameters :
|
2021-12-29 21:30:11 +00:00
|
|
|
VECTOR2I size = aText->GetTextSize();
|
|
|
|
VECTOR2I pos = aText->GetTextPos();
|
2021-12-29 17:31:40 +00:00
|
|
|
int thickness = aText->GetEffectiveTextPenWidth();
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-12-29 17:31:40 +00:00
|
|
|
if( aText->IsMirrored() )
|
2015-06-26 13:41:56 +00:00
|
|
|
size.x = -size.x; // Text is mirrored
|
2012-09-24 16:03:03 +00:00
|
|
|
|
|
|
|
// Non bold texts thickness is clamped at 1/6 char size by the low level draw function.
|
|
|
|
// but in Pcbnew we do not manage bold texts and thickness up to 1/4 char size
|
|
|
|
// (like bold text) and we manage the thickness.
|
|
|
|
// So we set bold flag to true
|
2020-05-01 16:24:01 +00:00
|
|
|
bool allow_bold = true;
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2016-09-19 11:01:36 +00:00
|
|
|
GBR_METADATA gbr_metadata;
|
2021-03-14 11:37:13 +00:00
|
|
|
|
2021-12-29 17:31:40 +00:00
|
|
|
if( IsCopperLayer( aText->GetLayer() ) )
|
2021-03-14 11:37:13 +00:00
|
|
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_NONCONDUCTOR );
|
|
|
|
|
2016-09-19 11:01:36 +00:00
|
|
|
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_CMP );
|
2021-12-29 17:31:40 +00:00
|
|
|
const FOOTPRINT* parent = static_cast<const FOOTPRINT*> ( aText->GetParent() );
|
2016-09-19 11:01:36 +00:00
|
|
|
gbr_metadata.SetCmpReference( parent->GetReference() );
|
|
|
|
|
2020-05-13 16:15:35 +00:00
|
|
|
m_plotter->SetCurrentLineWidth( thickness );
|
|
|
|
|
2021-12-29 17:31:40 +00:00
|
|
|
m_plotter->Text( pos, aColor, aText->GetShownText(), aText->GetDrawRotation(), size,
|
|
|
|
aText->GetHorizJustify(), aText->GetVertJustify(), thickness,
|
2022-01-07 00:47:23 +00:00
|
|
|
aText->IsItalic(), allow_bold, false, aText->GetDrawFont(), &gbr_metadata );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-11 16:59:28 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotDimension( const PCB_DIMENSION_BASE* aDim )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2014-06-24 16:17:18 +00:00
|
|
|
if( !m_layerMask[aDim->GetLayer()] )
|
2012-09-24 16:03:03 +00:00
|
|
|
return;
|
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
PCB_SHAPE draw;
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-07-17 19:56:18 +00:00
|
|
|
draw.SetStroke( STROKE_PARAMS( aDim->GetLineThickness(), PLOT_DASH_TYPE::SOLID ) );
|
2012-09-24 16:03:03 +00:00
|
|
|
draw.SetLayer( aDim->GetLayer() );
|
|
|
|
|
2020-03-30 01:43:18 +00:00
|
|
|
COLOR4D color = ColorSettings()->GetColor( aDim->GetLayer() );
|
2014-06-24 16:17:18 +00:00
|
|
|
|
2017-08-04 12:43:02 +00:00
|
|
|
// Set plot color (change WHITE to LIGHTGRAY because
|
|
|
|
// the white items are not seen on a white paper or screen
|
|
|
|
m_plotter->SetColor( color != WHITE ? color : LIGHTGRAY);
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2022-01-30 10:52:52 +00:00
|
|
|
PlotPcbText( &aDim->Text(), aDim->GetLayer() );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2020-09-12 20:09:40 +00:00
|
|
|
for( const std::shared_ptr<SHAPE>& shape : aDim->GetShapes() )
|
2020-09-09 03:17:08 +00:00
|
|
|
{
|
2020-09-12 20:09:40 +00:00
|
|
|
switch( shape->Type() )
|
|
|
|
{
|
|
|
|
case SH_SEGMENT:
|
|
|
|
{
|
|
|
|
const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
|
|
|
|
|
2021-07-21 18:31:25 +00:00
|
|
|
draw.SetShape( SHAPE_T::SEGMENT );
|
2022-01-01 18:08:03 +00:00
|
|
|
draw.SetStart( seg.A );
|
|
|
|
draw.SetEnd( seg.B );
|
2020-09-12 20:09:40 +00:00
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
PlotPcbShape( &draw );
|
2020-09-12 20:09:40 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SH_CIRCLE:
|
|
|
|
{
|
2022-01-01 18:08:03 +00:00
|
|
|
VECTOR2I start( shape->Centre() );
|
2020-09-12 20:09:40 +00:00
|
|
|
int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
|
|
|
|
|
2021-07-21 18:31:25 +00:00
|
|
|
draw.SetShape( SHAPE_T::CIRCLE );
|
2020-11-14 01:16:02 +00:00
|
|
|
draw.SetFilled( false );
|
2020-09-12 20:09:40 +00:00
|
|
|
draw.SetStart( start );
|
2022-01-01 18:08:03 +00:00
|
|
|
draw.SetEnd( VECTOR2I( start.x + radius, start.y ) );
|
2020-09-12 20:09:40 +00:00
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
PlotPcbShape( &draw );
|
2020-09-12 20:09:40 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2020-09-09 03:17:08 +00:00
|
|
|
}
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotPcbTarget( const PCB_TARGET* aMire )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-03-06 09:27:41 +00:00
|
|
|
int dx1, dx2, dy1, dy2, radius;
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
if( !m_layerMask[aMire->GetLayer()] )
|
2012-09-24 16:03:03 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
m_plotter->SetColor( getColor( aMire->GetLayer() ) );
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
PCB_SHAPE draw;
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-07-21 18:31:25 +00:00
|
|
|
draw.SetShape( SHAPE_T::CIRCLE );
|
2020-11-14 01:16:02 +00:00
|
|
|
draw.SetFilled( false );
|
2021-07-17 19:56:18 +00:00
|
|
|
draw.SetStroke( STROKE_PARAMS( aMire->GetWidth(), PLOT_DASH_TYPE::SOLID ) );
|
2012-09-24 16:03:03 +00:00
|
|
|
draw.SetLayer( aMire->GetLayer() );
|
|
|
|
draw.SetStart( aMire->GetPosition() );
|
|
|
|
radius = aMire->GetSize() / 3;
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2012-09-24 16:03:03 +00:00
|
|
|
if( aMire->GetShape() ) // shape X
|
|
|
|
radius = aMire->GetSize() / 2;
|
|
|
|
|
|
|
|
// Draw the circle
|
2022-01-01 18:08:03 +00:00
|
|
|
draw.SetEnd( VECTOR2I( draw.GetStart().x + radius, draw.GetStart().y ) );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
PlotPcbShape( &draw );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-07-21 18:31:25 +00:00
|
|
|
draw.SetShape( SHAPE_T::SEGMENT );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
|
|
|
radius = aMire->GetSize() / 2;
|
|
|
|
dx1 = radius;
|
|
|
|
dy1 = 0;
|
|
|
|
dx2 = 0;
|
|
|
|
dy2 = radius;
|
|
|
|
|
|
|
|
if( aMire->GetShape() ) // Shape X
|
|
|
|
{
|
|
|
|
dx1 = dy1 = radius;
|
|
|
|
dx2 = dx1;
|
|
|
|
dy2 = -dy1;
|
|
|
|
}
|
|
|
|
|
2022-01-01 18:08:03 +00:00
|
|
|
VECTOR2I mirePos( aMire->GetPosition() );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
|
|
|
// Draw the X or + shape:
|
2022-01-01 18:08:03 +00:00
|
|
|
draw.SetStart( VECTOR2I( mirePos.x - dx1, mirePos.y - dy1 ) );
|
|
|
|
draw.SetEnd( VECTOR2I( mirePos.x + dx1, mirePos.y + dy1 ) );
|
2020-10-04 23:34:59 +00:00
|
|
|
PlotPcbShape( &draw );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2022-01-01 18:08:03 +00:00
|
|
|
draw.SetStart( VECTOR2I( mirePos.x - dx2, mirePos.y - dy2 ) );
|
|
|
|
draw.SetEnd( VECTOR2I( mirePos.x + dx2, mirePos.y + dy2 ) );
|
2020-10-04 23:34:59 +00:00
|
|
|
PlotPcbShape( &draw );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotFootprintGraphicItems( const FOOTPRINT* aFootprint )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-03-06 09:27:41 +00:00
|
|
|
for( const BOARD_ITEM* item : aFootprint->GraphicalItems() )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-12-05 21:56:55 +00:00
|
|
|
if( aFootprint->GetPrivateLayers().test( item->GetLayer() ) )
|
|
|
|
continue;
|
|
|
|
|
2022-01-30 10:52:52 +00:00
|
|
|
switch( item->Type() )
|
|
|
|
{
|
|
|
|
case PCB_FP_SHAPE_T:
|
2021-12-04 23:52:00 +00:00
|
|
|
{
|
|
|
|
const FP_SHAPE* shape = static_cast<const FP_SHAPE*>( item );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-12-04 23:52:00 +00:00
|
|
|
if( m_layerMask[ shape->GetLayer() ] )
|
2022-01-30 10:52:52 +00:00
|
|
|
PlotFootprintShape( shape );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PCB_FP_TEXTBOX_T:
|
|
|
|
{
|
|
|
|
const FP_TEXTBOX* textbox = static_cast<const FP_TEXTBOX*>( item );
|
|
|
|
|
|
|
|
if( m_layerMask[ textbox->GetLayer() ] )
|
|
|
|
{
|
|
|
|
PlotPcbText( textbox, textbox->GetLayer() );
|
|
|
|
PlotFootprintShape( textbox );
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2021-12-04 23:52:00 +00:00
|
|
|
}
|
2022-01-30 10:52:52 +00:00
|
|
|
|
|
|
|
case PCB_DIM_ALIGNED_T:
|
|
|
|
case PCB_DIM_CENTER_T:
|
|
|
|
case PCB_DIM_RADIAL_T:
|
|
|
|
case PCB_DIM_ORTHOGONAL_T:
|
|
|
|
case PCB_DIM_LEADER_T:
|
2021-12-04 23:52:00 +00:00
|
|
|
{
|
|
|
|
const PCB_DIMENSION_BASE* dimension = static_cast<const PCB_DIMENSION_BASE*>( item );
|
|
|
|
|
|
|
|
if( m_layerMask[ dimension->GetLayer() ] )
|
|
|
|
PlotDimension( dimension );
|
2022-01-30 10:52:52 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PCB_FP_TEXT_T:
|
|
|
|
// Plotted in PlotFootprintTextItem()
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
UNIMPLEMENTED_FOR( item->GetClass() );
|
2021-12-04 23:52:00 +00:00
|
|
|
}
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-30 10:52:52 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotFootprintShape( const FP_SHAPE* aShape )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2020-10-04 23:34:59 +00:00
|
|
|
if( aShape->Type() != PCB_FP_SHAPE_T )
|
2012-09-24 16:03:03 +00:00
|
|
|
return;
|
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
m_plotter->SetColor( getColor( aShape->GetLayer() ) );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-07-17 19:56:18 +00:00
|
|
|
bool sketch = GetPlotMode() == SKETCH;
|
|
|
|
int thickness = aShape->GetWidth();
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2016-09-19 11:01:36 +00:00
|
|
|
GBR_METADATA gbr_metadata;
|
|
|
|
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_CMP );
|
2021-03-06 09:27:41 +00:00
|
|
|
const FOOTPRINT* parent = static_cast<const FOOTPRINT*> ( aShape->GetParent() );
|
2016-09-19 11:01:36 +00:00
|
|
|
gbr_metadata.SetCmpReference( parent->GetReference() );
|
|
|
|
|
|
|
|
bool isOnCopperLayer = ( m_layerMask & LSET::AllCuMask() ).any();
|
|
|
|
|
2021-03-14 11:37:13 +00:00
|
|
|
if( aShape->GetLayer() == Edge_Cuts ) // happens also when plotting copper layers
|
2016-09-19 11:01:36 +00:00
|
|
|
{
|
2021-03-14 11:37:13 +00:00
|
|
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_EDGECUT );
|
2016-09-19 11:01:36 +00:00
|
|
|
}
|
2021-03-14 11:37:13 +00:00
|
|
|
else if( isOnCopperLayer ) // only for items not on Edge_Cuts.
|
2016-09-19 11:01:36 +00:00
|
|
|
{
|
2021-03-14 11:37:13 +00:00
|
|
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_ETCHEDCMP );
|
|
|
|
gbr_metadata.SetCopper( true );
|
2016-09-19 11:01:36 +00:00
|
|
|
}
|
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
int radius; // Circle/arc radius.
|
|
|
|
PLOT_DASH_TYPE lineStyle = aShape->GetStroke().GetPlotStyle();
|
2019-11-05 10:07:07 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
if( lineStyle <= PLOT_DASH_TYPE::FIRST_TYPE )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-08-25 23:14:36 +00:00
|
|
|
switch( aShape->GetShape() )
|
2020-06-19 20:46:43 +00:00
|
|
|
{
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::SEGMENT:
|
|
|
|
m_plotter->ThickSegment( aShape->GetStart(), aShape->GetEnd(), thickness, GetPlotMode(),
|
|
|
|
&gbr_metadata );
|
|
|
|
break;
|
2020-11-14 01:16:02 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::RECT:
|
2020-06-19 20:46:43 +00:00
|
|
|
{
|
2022-01-01 06:04:08 +00:00
|
|
|
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
|
2020-06-19 20:46:43 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
if( sketch || thickness > 0 )
|
|
|
|
{
|
|
|
|
m_plotter->ThickSegment( pts[0], pts[1], thickness, GetPlotMode(), &gbr_metadata );
|
|
|
|
m_plotter->ThickSegment( pts[1], pts[2], thickness, GetPlotMode(), &gbr_metadata );
|
|
|
|
m_plotter->ThickSegment( pts[2], pts[3], thickness, GetPlotMode(), &gbr_metadata );
|
|
|
|
m_plotter->ThickSegment( pts[3], pts[0], thickness, GetPlotMode(), &gbr_metadata );
|
|
|
|
}
|
2020-06-19 20:46:43 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
if( !sketch && aShape->IsFilled() )
|
|
|
|
{
|
|
|
|
SHAPE_LINE_CHAIN poly;
|
2020-06-15 19:50:20 +00:00
|
|
|
|
2022-01-01 06:04:08 +00:00
|
|
|
for( const VECTOR2I& pt : pts )
|
2021-08-25 23:14:36 +00:00
|
|
|
poly.Append( pt );
|
2020-06-19 20:46:43 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
m_plotter->PlotPoly( poly, FILL_T::FILLED_SHAPE, -1, &gbr_metadata );
|
|
|
|
}
|
2021-07-17 19:56:18 +00:00
|
|
|
}
|
2021-08-25 23:14:36 +00:00
|
|
|
break;
|
2020-06-19 20:46:43 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::CIRCLE:
|
|
|
|
radius = KiROUND( GetLineLength( aShape->GetStart(), aShape->GetEnd() ) );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
if( aShape->IsFilled() )
|
|
|
|
{
|
|
|
|
m_plotter->FilledCircle( aShape->GetStart(), radius * 2 + thickness, GetPlotMode(),
|
|
|
|
&gbr_metadata );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_plotter->ThickCircle( aShape->GetStart(), radius * 2, thickness, GetPlotMode(),
|
|
|
|
&gbr_metadata );
|
|
|
|
}
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
break;
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::ARC:
|
2018-01-24 13:22:43 +00:00
|
|
|
{
|
2021-08-25 23:14:36 +00:00
|
|
|
radius = KiROUND( GetLineLength( aShape->GetCenter(), aShape->GetStart() ) );
|
2022-01-14 15:34:41 +00:00
|
|
|
EDA_ANGLE startAngle( aShape->GetStart() - aShape->GetCenter() );
|
|
|
|
EDA_ANGLE endAngle = startAngle + aShape->GetArcAngle();
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
// when startAngle == endAngle ThickArc() doesn't know whether it's 0 deg and 360 deg
|
2022-01-14 15:34:41 +00:00
|
|
|
if( std::abs( aShape->GetArcAngle().AsDegrees() ) == 360.0 )
|
2018-01-24 13:22:43 +00:00
|
|
|
{
|
2021-08-25 23:14:36 +00:00
|
|
|
m_plotter->ThickCircle( aShape->GetCenter(), radius * 2, thickness, GetPlotMode(),
|
|
|
|
&gbr_metadata );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-16 01:06:25 +00:00
|
|
|
m_plotter->ThickArc( aShape->GetCenter(), -endAngle, -startAngle, radius,
|
|
|
|
thickness, GetPlotMode(), &gbr_metadata );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
2021-08-25 23:14:36 +00:00
|
|
|
}
|
|
|
|
break;
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::POLY:
|
|
|
|
if( aShape->IsPolyShapeValid() )
|
2018-12-02 15:33:12 +00:00
|
|
|
{
|
2022-01-01 06:04:08 +00:00
|
|
|
std::vector<VECTOR2I> cornerList;
|
2021-08-25 23:14:36 +00:00
|
|
|
aShape->DupPolyPointsList( cornerList );
|
|
|
|
|
|
|
|
// We must compute board coordinates from m_PolyList which are relative to the parent
|
|
|
|
// position at orientation 0
|
|
|
|
const FOOTPRINT *parentFootprint = aShape->GetParentFootprint();
|
|
|
|
|
|
|
|
if( parentFootprint )
|
2018-12-02 15:33:12 +00:00
|
|
|
{
|
2021-08-25 23:14:36 +00:00
|
|
|
for( unsigned ii = 0; ii < cornerList.size(); ++ii )
|
|
|
|
{
|
2022-01-01 06:04:08 +00:00
|
|
|
RotatePoint( cornerList[ii], parentFootprint->GetOrientation() );
|
|
|
|
cornerList[ii] += parentFootprint->GetPosition();
|
2021-08-25 23:14:36 +00:00
|
|
|
}
|
2018-12-02 15:33:12 +00:00
|
|
|
}
|
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
if( sketch || thickness > 0 )
|
|
|
|
{
|
|
|
|
for( size_t i = 1; i < cornerList.size(); i++ )
|
|
|
|
{
|
|
|
|
m_plotter->ThickSegment( cornerList[i - 1], cornerList[i], thickness,
|
|
|
|
GetPlotMode(), &gbr_metadata );
|
|
|
|
}
|
2018-12-02 15:33:12 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
m_plotter->ThickSegment( cornerList.back(), cornerList.front(), thickness,
|
|
|
|
GetPlotMode(), &gbr_metadata );
|
2020-11-14 01:16:02 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
}
|
2019-08-06 04:23:57 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
if( !sketch && aShape->IsFilled() )
|
|
|
|
{
|
|
|
|
// This must be simplified and fractured to prevent overlapping polygons
|
|
|
|
// from generating invalid Gerber files
|
2019-08-06 04:23:57 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
SHAPE_LINE_CHAIN line( cornerList );
|
|
|
|
SHAPE_POLY_SET tmpPoly;
|
2019-08-06 04:23:57 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
line.SetClosed( true );
|
|
|
|
tmpPoly.AddOutline( line );
|
|
|
|
tmpPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
|
|
|
|
|
|
|
|
for( int jj = 0; jj < tmpPoly.OutlineCount(); ++jj )
|
|
|
|
{
|
|
|
|
SHAPE_LINE_CHAIN &poly = tmpPoly.Outline( jj );
|
|
|
|
m_plotter->PlotPoly( poly, FILL_T::FILLED_SHAPE, thickness, &gbr_metadata );
|
|
|
|
}
|
2019-08-06 04:23:57 +00:00
|
|
|
}
|
2018-12-02 15:33:12 +00:00
|
|
|
}
|
2021-07-19 23:56:05 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
break;
|
2019-11-05 10:07:07 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::BEZIER:
|
|
|
|
m_plotter->BezierCurve( aShape->GetStart(), aShape->GetBezierC1(),
|
|
|
|
aShape->GetBezierC2(), aShape->GetEnd(), 0, thickness );
|
|
|
|
break;
|
2019-11-05 10:07:07 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
default:
|
|
|
|
wxASSERT_MSG( false, "Unhandled FP_SHAPE shape" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
|
|
|
|
|
|
|
|
for( SHAPE* shape : shapes )
|
|
|
|
{
|
|
|
|
STROKE_PARAMS::Stroke( shape, lineStyle, thickness, m_plotter->RenderSettings(),
|
2022-01-01 18:08:03 +00:00
|
|
|
[&]( const VECTOR2I& a, const VECTOR2I& b )
|
2021-08-25 23:14:36 +00:00
|
|
|
{
|
|
|
|
m_plotter->ThickSegment( a, b, thickness, GetPlotMode(),
|
|
|
|
&gbr_metadata );
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
for( SHAPE* shape : shapes )
|
|
|
|
delete shape;
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-30 10:52:52 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotPcbText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2022-01-07 00:47:23 +00:00
|
|
|
wxString shownText( aText->GetShownText() );
|
|
|
|
KIFONT::FONT* font = aText->GetDrawFont();
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2014-09-13 18:15:45 +00:00
|
|
|
if( shownText.IsEmpty() )
|
2012-09-24 16:03:03 +00:00
|
|
|
return;
|
|
|
|
|
2022-01-30 10:52:52 +00:00
|
|
|
if( !m_layerMask[aLayer] )
|
2012-09-24 16:03:03 +00:00
|
|
|
return;
|
|
|
|
|
2016-09-19 11:01:36 +00:00
|
|
|
GBR_METADATA gbr_metadata;
|
|
|
|
|
2022-01-30 10:52:52 +00:00
|
|
|
if( IsCopperLayer( aLayer ) )
|
2016-09-19 11:01:36 +00:00
|
|
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_NONCONDUCTOR );
|
|
|
|
|
2022-01-30 10:52:52 +00:00
|
|
|
COLOR4D color = getColor( aLayer );
|
2017-07-31 12:28:35 +00:00
|
|
|
m_plotter->SetColor( color );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-12-29 21:30:11 +00:00
|
|
|
VECTOR2I size = aText->GetTextSize();
|
|
|
|
VECTOR2I pos = aText->GetTextPos();
|
2020-10-04 23:34:59 +00:00
|
|
|
int thickness = aText->GetEffectiveTextPenWidth();
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
if( aText->IsMirrored() )
|
2012-09-24 16:03:03 +00:00
|
|
|
size.x = -size.x;
|
|
|
|
|
|
|
|
// Non bold texts thickness is clamped at 1/6 char size by the low level draw function.
|
|
|
|
// but in Pcbnew we do not manage bold texts and thickness up to 1/4 char size
|
|
|
|
// (like bold text) and we manage the thickness.
|
|
|
|
// So we set bold flag to true
|
2020-05-01 16:24:01 +00:00
|
|
|
bool allow_bold = true;
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2020-04-21 20:17:01 +00:00
|
|
|
m_plotter->SetCurrentLineWidth( thickness );
|
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
if( aText->IsMultilineAllowed() )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2022-01-01 06:04:08 +00:00
|
|
|
std::vector<VECTOR2I> positions;
|
2015-01-15 20:01:53 +00:00
|
|
|
wxArrayString strings_list;
|
|
|
|
wxStringSplit( shownText, strings_list, '\n' );
|
|
|
|
positions.reserve( strings_list.Count() );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2020-11-24 22:16:41 +00:00
|
|
|
aText->GetLinePositions( positions, strings_list.Count() );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2015-01-15 20:01:53 +00:00
|
|
|
wxString& txt = strings_list.Item( ii );
|
2022-01-30 10:52:52 +00:00
|
|
|
m_plotter->Text( positions[ii], color, txt, aText->GetDrawRotation(), size,
|
2021-12-28 22:13:54 +00:00
|
|
|
aText->GetHorizJustify(), aText->GetVertJustify(), thickness,
|
2022-01-07 00:47:23 +00:00
|
|
|
aText->IsItalic(), allow_bold, false, font, &gbr_metadata );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-30 10:52:52 +00:00
|
|
|
m_plotter->Text( pos, color, shownText, aText->GetDrawRotation(), size,
|
2021-12-28 22:13:54 +00:00
|
|
|
aText->GetHorizJustify(), aText->GetVertJustify(), thickness,
|
2022-01-07 00:47:23 +00:00
|
|
|
aText->IsItalic(), allow_bold, false, font, &gbr_metadata );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotFilledAreas( const ZONE* aZone, const SHAPE_POLY_SET& polysList )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2015-07-27 19:45:57 +00:00
|
|
|
if( polysList.IsEmpty() )
|
2012-09-24 16:03:03 +00:00
|
|
|
return;
|
|
|
|
|
2016-09-19 11:01:36 +00:00
|
|
|
GBR_METADATA gbr_metadata;
|
|
|
|
|
|
|
|
bool isOnCopperLayer = aZone->IsOnCopperLayer();
|
|
|
|
|
|
|
|
if( isOnCopperLayer )
|
|
|
|
{
|
|
|
|
gbr_metadata.SetNetName( aZone->GetNetname() );
|
2017-05-03 18:04:31 +00:00
|
|
|
gbr_metadata.SetCopper( true );
|
2016-09-19 11:01:36 +00:00
|
|
|
|
|
|
|
// Zones with no net name can exist.
|
|
|
|
// they are not used to connect items, so the aperture attribute cannot
|
|
|
|
// be set as conductor
|
|
|
|
if( aZone->GetNetname().IsEmpty() )
|
2021-01-03 13:59:23 +00:00
|
|
|
{
|
2021-08-17 19:41:08 +00:00
|
|
|
gbr_metadata.SetApertureAttrib(
|
|
|
|
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_NONCONDUCTOR );
|
2021-01-03 13:59:23 +00:00
|
|
|
}
|
2016-09-19 11:01:36 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_CONDUCTOR );
|
|
|
|
gbr_metadata.SetNetAttribType( GBR_NETLIST_METADATA::GBR_NETINFO_NET );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-24 16:03:03 +00:00
|
|
|
m_plotter->SetColor( getColor( aZone->GetLayer() ) );
|
|
|
|
|
2020-06-28 08:37:36 +00:00
|
|
|
m_plotter->StartBlock( nullptr ); // Clean current object attributes
|
|
|
|
|
2012-09-24 16:03:03 +00:00
|
|
|
/* Plot all filled areas: filled areas have a filled area and a thick
|
2019-08-25 10:10:48 +00:00
|
|
|
* outline (depending on the fill area option we must plot the filled area itself
|
|
|
|
* and plot the thick outline itself, if the thickness has meaning (at least is > 1)
|
2012-09-24 16:03:03 +00:00
|
|
|
*
|
|
|
|
* in non filled mode the outline is plotted, but not the filling items
|
|
|
|
*/
|
2019-08-25 10:10:48 +00:00
|
|
|
int outline_thickness = aZone->GetFilledPolysUseThickness() ? aZone->GetMinThickness() : 0;
|
|
|
|
|
2019-08-27 11:32:00 +00:00
|
|
|
for( int idx = 0; idx < polysList.OutlineCount(); ++idx )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-03-06 09:27:41 +00:00
|
|
|
const SHAPE_LINE_CHAIN& outline = polysList.Outline( idx );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-06-03 20:31:25 +00:00
|
|
|
// Plot the current filled area (as region for Gerber plotter
|
|
|
|
// to manage attributes) and its outline for thick outline
|
|
|
|
if( GetPlotMode() == FILLED )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-06-03 20:31:25 +00:00
|
|
|
if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-06-03 20:31:25 +00:00
|
|
|
if( outline_thickness > 0 )
|
2021-01-03 13:59:23 +00:00
|
|
|
{
|
2021-07-18 23:08:54 +00:00
|
|
|
m_plotter->PlotPoly( outline, FILL_T::NO_FILL, outline_thickness,
|
|
|
|
&gbr_metadata );
|
2021-07-06 11:57:47 +00:00
|
|
|
|
|
|
|
// Ensure the outline is closed:
|
|
|
|
int last_idx = outline.PointCount() - 1;
|
|
|
|
|
|
|
|
if( outline.CPoint( 0 ) != outline.CPoint( last_idx ) )
|
|
|
|
{
|
2022-01-01 18:08:03 +00:00
|
|
|
m_plotter->ThickSegment( VECTOR2I( outline.CPoint( 0 ) ),
|
|
|
|
VECTOR2I( outline.CPoint( last_idx ) ),
|
2021-07-18 23:08:54 +00:00
|
|
|
outline_thickness, GetPlotMode(), &gbr_metadata );
|
2021-07-06 11:57:47 +00:00
|
|
|
}
|
2021-01-03 13:59:23 +00:00
|
|
|
}
|
2021-06-03 20:31:25 +00:00
|
|
|
|
2021-07-19 23:56:05 +00:00
|
|
|
static_cast<GERBER_PLOTTER*>( m_plotter )->PlotGerberRegion( outline,
|
|
|
|
&gbr_metadata );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-07-18 23:08:54 +00:00
|
|
|
m_plotter->PlotPoly( outline, FILL_T::FILLED_SHAPE, outline_thickness,
|
|
|
|
&gbr_metadata );
|
2021-06-03 20:31:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( outline_thickness )
|
|
|
|
{
|
2021-07-06 11:57:47 +00:00
|
|
|
int last_idx = outline.PointCount() - 1;
|
|
|
|
|
|
|
|
for( int jj = 1; jj <= last_idx; jj++ )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2022-01-01 18:08:03 +00:00
|
|
|
m_plotter->ThickSegment( VECTOR2I( outline.CPoint( jj - 1 ) ),
|
|
|
|
VECTOR2I( outline.CPoint( jj ) ),
|
2021-06-03 20:31:25 +00:00
|
|
|
outline_thickness,
|
2021-07-06 11:57:47 +00:00
|
|
|
GetPlotMode(), &gbr_metadata );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the outline is closed:
|
|
|
|
if( outline.CPoint( 0 ) != outline.CPoint( last_idx ) )
|
|
|
|
{
|
2022-01-01 18:08:03 +00:00
|
|
|
m_plotter->ThickSegment( VECTOR2I( outline.CPoint( 0 ) ),
|
|
|
|
VECTOR2I( outline.CPoint( last_idx ) ),
|
2021-07-06 11:57:47 +00:00
|
|
|
outline_thickness,
|
2021-06-03 20:31:25 +00:00
|
|
|
GetPlotMode(), &gbr_metadata );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-03 20:31:25 +00:00
|
|
|
|
|
|
|
m_plotter->SetCurrentLineWidth( -1 );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-28 08:37:36 +00:00
|
|
|
|
|
|
|
m_plotter->EndBlock( nullptr ); // Clear object attributes
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-06 09:27:41 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotPcbShape( const PCB_SHAPE* aShape )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2020-10-04 23:34:59 +00:00
|
|
|
if( !m_layerMask[aShape->GetLayer()] )
|
2012-09-24 16:03:03 +00:00
|
|
|
return;
|
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
bool sketch = GetPlotMode() == SKETCH;
|
|
|
|
int thickness = aShape->GetWidth();
|
|
|
|
PLOT_DASH_TYPE lineStyle = aShape->GetStroke().GetPlotStyle();
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
m_plotter->SetColor( getColor( aShape->GetLayer() ) );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2016-09-19 11:01:36 +00:00
|
|
|
GBR_METADATA gbr_metadata;
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
if( aShape->GetLayer() == Edge_Cuts )
|
2019-10-09 13:46:35 +00:00
|
|
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_EDGECUT );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2020-10-04 23:34:59 +00:00
|
|
|
if( IsCopperLayer( aShape->GetLayer() ) )
|
|
|
|
// Graphic items (PCB_SHAPE, TEXT) having no net have the NonConductor attribute
|
2020-03-19 11:53:52 +00:00
|
|
|
// Graphic items having a net have the Conductor attribute, but are not (yet?)
|
|
|
|
// supported in Pcbnew
|
|
|
|
gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_NONCONDUCTOR );
|
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
if( lineStyle <= PLOT_DASH_TYPE::FIRST_TYPE )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-08-25 23:14:36 +00:00
|
|
|
switch( aShape->GetShape() )
|
2021-07-17 19:56:18 +00:00
|
|
|
{
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::SEGMENT:
|
|
|
|
m_plotter->ThickSegment( aShape->GetStart(), aShape->GetEnd(), thickness, GetPlotMode(),
|
|
|
|
&gbr_metadata );
|
|
|
|
break;
|
2020-11-14 01:16:02 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::CIRCLE:
|
|
|
|
if( aShape->IsFilled() )
|
|
|
|
{
|
|
|
|
m_plotter->FilledCircle( aShape->GetStart(), aShape->GetRadius() * 2 + thickness,
|
|
|
|
GetPlotMode(), &gbr_metadata );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_plotter->ThickCircle( aShape->GetStart(), aShape->GetRadius() * 2, thickness,
|
|
|
|
GetPlotMode(), &gbr_metadata );
|
|
|
|
}
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
break;
|
2018-02-04 16:22:14 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::ARC:
|
2020-11-14 01:16:02 +00:00
|
|
|
{
|
2022-01-14 15:34:41 +00:00
|
|
|
EDA_ANGLE startAngle( aShape->GetStart() - aShape->GetCenter() );
|
|
|
|
EDA_ANGLE endAngle = startAngle + aShape->GetArcAngle();
|
2021-08-25 23:14:36 +00:00
|
|
|
|
|
|
|
// when startAngle == endAngle ThickArc() doesn't know whether it's 0 deg and 360 deg
|
2022-01-14 15:34:41 +00:00
|
|
|
if( std::abs( aShape->GetArcAngle().AsDegrees() ) == 360.0 )
|
2021-08-25 23:14:36 +00:00
|
|
|
{
|
|
|
|
m_plotter->ThickCircle( aShape->GetCenter(), aShape->GetRadius() * 2, thickness,
|
|
|
|
GetPlotMode(), &gbr_metadata );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-16 01:06:25 +00:00
|
|
|
m_plotter->ThickArc( aShape->GetCenter(), -endAngle, -startAngle,
|
|
|
|
aShape->GetRadius(), thickness, GetPlotMode(), &gbr_metadata );
|
2021-08-25 23:14:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2020-11-14 01:16:02 +00:00
|
|
|
}
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::BEZIER:
|
|
|
|
m_plotter->BezierCurve( aShape->GetStart(), aShape->GetBezierC1(),
|
|
|
|
aShape->GetBezierC2(), aShape->GetEnd(), 0, thickness );
|
|
|
|
break;
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::POLY:
|
|
|
|
if( aShape->IsPolyShapeValid() )
|
2018-12-02 04:41:17 +00:00
|
|
|
{
|
2021-08-25 23:14:36 +00:00
|
|
|
if( sketch || thickness > 0 )
|
2018-12-02 04:41:17 +00:00
|
|
|
{
|
2021-08-25 23:14:36 +00:00
|
|
|
for( auto it = aShape->GetPolyShape().CIterateSegments( 0 ); it; it++ )
|
|
|
|
{
|
|
|
|
auto seg = it.Get();
|
2022-01-01 18:08:03 +00:00
|
|
|
m_plotter->ThickSegment( seg.A, seg.B, thickness, GetPlotMode(),
|
|
|
|
&gbr_metadata );
|
2021-08-25 23:14:36 +00:00
|
|
|
}
|
2018-12-02 04:41:17 +00:00
|
|
|
}
|
2020-11-14 01:16:02 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
if( !sketch && aShape->IsFilled() )
|
|
|
|
{
|
|
|
|
m_plotter->SetCurrentLineWidth( thickness, &gbr_metadata );
|
2021-07-19 23:56:05 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
// Draw the polygon: only one polygon is expected
|
|
|
|
// However we provide a multi polygon shape drawing
|
|
|
|
// ( for the future or to show a non expected shape )
|
|
|
|
// This must be simplified and fractured to prevent overlapping polygons
|
|
|
|
// from generating invalid Gerber files
|
|
|
|
auto tmpPoly = SHAPE_POLY_SET( aShape->GetPolyShape() );
|
|
|
|
tmpPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
|
2018-12-21 01:03:55 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
for( int jj = 0; jj < tmpPoly.OutlineCount(); ++jj )
|
|
|
|
{
|
|
|
|
SHAPE_LINE_CHAIN& poly = tmpPoly.Outline( jj );
|
|
|
|
m_plotter->PlotPoly( poly, FILL_T::FILLED_SHAPE, thickness, &gbr_metadata );
|
|
|
|
}
|
2018-12-02 04:41:17 +00:00
|
|
|
}
|
2017-11-16 11:09:24 +00:00
|
|
|
}
|
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
break;
|
2020-07-17 09:26:35 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
case SHAPE_T::RECT:
|
2020-07-17 09:26:35 +00:00
|
|
|
{
|
2022-01-01 06:04:08 +00:00
|
|
|
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
|
2020-11-14 01:16:02 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
if( sketch || thickness > 0 )
|
|
|
|
{
|
|
|
|
m_plotter->ThickSegment( pts[0], pts[1], thickness, GetPlotMode(), &gbr_metadata );
|
|
|
|
m_plotter->ThickSegment( pts[1], pts[2], thickness, GetPlotMode(), &gbr_metadata );
|
|
|
|
m_plotter->ThickSegment( pts[2], pts[3], thickness, GetPlotMode(), &gbr_metadata );
|
|
|
|
m_plotter->ThickSegment( pts[3], pts[0], thickness, GetPlotMode(), &gbr_metadata );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !sketch && aShape->IsFilled() )
|
|
|
|
{
|
|
|
|
SHAPE_LINE_CHAIN poly;
|
2020-07-17 09:26:35 +00:00
|
|
|
|
2022-01-01 06:04:08 +00:00
|
|
|
for( const VECTOR2I& pt : pts )
|
2021-08-25 23:14:36 +00:00
|
|
|
poly.Append( pt );
|
2020-07-17 09:26:35 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
m_plotter->PlotPoly( poly, FILL_T::FILLED_SHAPE, -1, &gbr_metadata );
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2020-07-17 09:26:35 +00:00
|
|
|
}
|
2021-07-19 23:56:05 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
default:
|
|
|
|
UNIMPLEMENTED_FOR( aShape->SHAPE_T_asString() );
|
|
|
|
}
|
2021-07-19 23:56:05 +00:00
|
|
|
}
|
2021-08-25 23:14:36 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
|
2020-07-17 09:26:35 +00:00
|
|
|
|
2021-08-25 23:14:36 +00:00
|
|
|
for( SHAPE* shape : shapes )
|
|
|
|
{
|
|
|
|
STROKE_PARAMS::Stroke( shape, lineStyle, thickness, m_plotter->RenderSettings(),
|
2022-01-01 18:08:03 +00:00
|
|
|
[&]( const VECTOR2I& a, const VECTOR2I& b )
|
2021-08-25 23:14:36 +00:00
|
|
|
{
|
|
|
|
m_plotter->ThickSegment( a, b, thickness, GetPlotMode(),
|
|
|
|
&gbr_metadata );
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
for( SHAPE* shape : shapes )
|
|
|
|
delete shape;
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2022-01-01 06:04:08 +00:00
|
|
|
void BRDITEMS_PLOTTER::plotOneDrillMark( PAD_DRILL_SHAPE_T aDrillShape, const VECTOR2I& aDrillPos,
|
2022-01-05 01:42:27 +00:00
|
|
|
const VECTOR2I& aDrillSize, const VECTOR2I& aPadSize,
|
2022-01-16 01:06:25 +00:00
|
|
|
const EDA_ANGLE& aOrientation, int aSmallDrill )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2022-01-05 01:42:27 +00:00
|
|
|
VECTOR2I drillSize = aDrillSize;
|
2021-07-26 23:47:26 +00:00
|
|
|
|
2012-09-24 16:03:03 +00:00
|
|
|
// Small drill marks have no significance when applied to slots
|
2015-08-23 19:40:33 +00:00
|
|
|
if( aSmallDrill && aDrillShape == PAD_DRILL_SHAPE_CIRCLE )
|
2021-07-26 23:47:26 +00:00
|
|
|
drillSize.x = std::min( aSmallDrill, drillSize.x );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
|
|
|
// Round holes only have x diameter, slots have both
|
2021-07-26 23:47:26 +00:00
|
|
|
drillSize.x -= getFineWidthAdj();
|
|
|
|
drillSize.x = Clamp( 1, drillSize.x, aPadSize.x - 1 );
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2015-08-23 19:40:33 +00:00
|
|
|
if( aDrillShape == PAD_DRILL_SHAPE_OBLONG )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-07-26 23:47:26 +00:00
|
|
|
drillSize.y -= getFineWidthAdj();
|
|
|
|
drillSize.y = Clamp( 1, drillSize.y, aPadSize.y - 1 );
|
2022-01-16 01:06:25 +00:00
|
|
|
|
2021-07-26 23:47:26 +00:00
|
|
|
m_plotter->FlashPadOval( aDrillPos, drillSize, aOrientation, GetPlotMode(), nullptr );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
else
|
2021-01-03 13:59:23 +00:00
|
|
|
{
|
2021-07-26 23:47:26 +00:00
|
|
|
m_plotter->FlashPadCircle( aDrillPos, drillSize.x, GetPlotMode(), nullptr );
|
2021-01-03 13:59:23 +00:00
|
|
|
}
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
|
2013-03-20 14:50:12 +00:00
|
|
|
|
2012-09-24 16:03:03 +00:00
|
|
|
void BRDITEMS_PLOTTER::PlotDrillMarks()
|
|
|
|
{
|
|
|
|
/* If small drills marks were requested prepare a clamp value to pass
|
|
|
|
to the helper function */
|
2021-01-23 17:02:58 +00:00
|
|
|
int smallDrill = GetDrillMarksType() == PCB_PLOT_PARAMS::SMALL_DRILL_SHAPE
|
2021-01-04 22:26:23 +00:00
|
|
|
? Millimeter2iu( ADVANCED_CFG::GetCfg().m_SmallDrillMarkSize ) : 0;
|
2012-09-24 16:03:03 +00:00
|
|
|
|
|
|
|
/* In the filled trace mode drill marks are drawn white-on-black to scrape
|
|
|
|
the underlying pad. This works only for drivers supporting color change,
|
|
|
|
obviously... it means that:
|
|
|
|
- PS, SVG and PDF output is correct (i.e. you have a 'donut' pad)
|
|
|
|
- In HPGL you can't see them
|
|
|
|
- In gerbers you can't see them, too. This is arguably the right thing to
|
|
|
|
do since having drill marks and high speed drill stations is a sure
|
|
|
|
recipe for broken tools and angry manufacturers. If you *really* want them
|
|
|
|
you could start a layer with negative polarity to scrape the film.
|
|
|
|
- In DXF they go into the 'WHITE' layer. This could be useful.
|
|
|
|
*/
|
2015-02-02 08:06:39 +00:00
|
|
|
if( GetPlotMode() == FILLED )
|
2012-09-24 16:03:03 +00:00
|
|
|
m_plotter->SetColor( WHITE );
|
|
|
|
|
2021-06-11 21:07:02 +00:00
|
|
|
for( PCB_TRACK* tracks : m_board->Tracks() )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-06-11 21:07:02 +00:00
|
|
|
const PCB_VIA* via = dyn_cast<const PCB_VIA*>( tracks );
|
2012-09-24 16:03:03 +00:00
|
|
|
|
2014-04-25 06:00:04 +00:00
|
|
|
if( via )
|
2019-04-10 09:19:16 +00:00
|
|
|
{
|
2015-08-23 19:40:33 +00:00
|
|
|
plotOneDrillMark( PAD_DRILL_SHAPE_CIRCLE, via->GetStart(),
|
2021-01-03 13:59:23 +00:00
|
|
|
wxSize( via->GetDrillValue(), 0 ),
|
2022-01-16 01:06:25 +00:00
|
|
|
wxSize( via->GetWidth(), 0 ), ANGLE_0, smallDrill );
|
2019-04-10 09:19:16 +00:00
|
|
|
}
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
|
2021-01-03 13:59:23 +00:00
|
|
|
for( FOOTPRINT* footprint : m_board->Footprints() )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
2021-01-03 13:59:23 +00:00
|
|
|
for( PAD* pad : footprint->Pads() )
|
2012-09-24 16:03:03 +00:00
|
|
|
{
|
|
|
|
if( pad->GetDrillSize().x == 0 )
|
|
|
|
continue;
|
|
|
|
|
2021-01-03 13:59:23 +00:00
|
|
|
plotOneDrillMark( pad->GetDrillShape(), pad->GetPosition(), pad->GetDrillSize(),
|
2022-01-16 01:06:25 +00:00
|
|
|
pad->GetSize(), pad->GetOrientation(), smallDrill );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-02 08:06:39 +00:00
|
|
|
if( GetPlotMode() == FILLED )
|
2021-01-03 13:59:23 +00:00
|
|
|
m_plotter->SetColor( BLACK );
|
2012-09-24 16:03:03 +00:00
|
|
|
}
|