KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_plot_edge_cuts_drill_marks.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
22
23#include <board.h>
24#include <footprint.h>
25#include <pad.h>
26#include <pcbplot.h>
29#include <pcb_plot_params.h>
30#include <layer_ids.h>
31#include <lset.h>
32
33#include <wx/filename.h>
34#include <wx/ffile.h>
35
36#include <memory>
37#include <regex>
38#include <string>
39
40BOOST_AUTO_TEST_SUITE( PlotEdgeCutsDrillMarks )
41
42// Regression for #24416: drill marks must never be flashed onto a layer the pad
43// isn't on (Edge_Cuts, paste, silk). Plot Edge_Cuts with drill marks enabled and
44// assert the gerber contains no flash (D03) apertures.
45BOOST_AUTO_TEST_CASE( NoDrillFlashesOnEdgeCuts )
46{
47 const int padDia = pcbIUScale.mmToIU( 1.4 );
48 const int drill = pcbIUScale.mmToIU( 0.8 );
49
50 BOARD board;
51 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( &board );
52 footprint->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 50.0 ), pcbIUScale.mmToIU( 50.0 ) ) );
53
54 PAD* pad = new PAD( footprint.get() );
55 pad->SetPadstackMode( PADSTACK::MODE::NORMAL );
56 pad->SetAttribute( PAD_ATTRIB::PTH );
58 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( padDia, padDia ) );
59 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
60 pad->SetDrillSize( VECTOR2I( drill, drill ) );
61 pad->SetLayerSet( LSET::AllCuMask() | LSET( { F_Mask, B_Mask } ) ); // THT pad: NOT on Edge_Cuts
62 pad->SetPosition( footprint->GetPosition() );
63 footprint->Add( pad );
64 board.Add( footprint.release() );
65
66 GERBER_PLOTTER plotter;
67 SIMPLE_RENDER_SETTINGS renderSettings;
68 plotter.SetRenderSettings( &renderSettings );
69
70 wxString gbrPath = wxFileName::CreateTempFileName( wxT( "kicad_gbr_24416" ) );
71 BOOST_REQUIRE( !gbrPath.IsEmpty() );
72 BOOST_REQUIRE( plotter.OpenFile( gbrPath ) );
73 plotter.SetViewport( VECTOR2I( 0, 0 ), pcbIUScale.IU_PER_MILS / 10, 1.0, false );
74 BOOST_REQUIRE( plotter.StartPlot( wxT( "1" ) ) );
75
76 PCB_PLOT_PARAMS plotOpts;
78 plotOpts.SetDrillMarksType( DRILL_MARKS::FULL_DRILL_SHAPE ); // triggers PlotDrillMarks()
79
80 PlotBoardLayers( &board, &plotter, LSEQ{ Edge_Cuts }, plotOpts );
81 BOOST_REQUIRE( plotter.EndPlot() );
82
83 wxFFile file( gbrPath, wxT( "rb" ) );
84 BOOST_REQUIRE( file.IsOpened() );
85 wxString contents;
86 BOOST_REQUIRE( file.ReadAll( &contents ) );
87 file.Close();
88 wxRemoveFile( gbrPath );
89
90 std::string buf = contents.ToStdString();
91 std::regex flashRe( R"(D0*3\*)" ); // D03 = flash a pad/aperture
92 long flashes = std::distance( std::sregex_iterator( buf.begin(), buf.end(), flashRe ), std::sregex_iterator() );
93
94 BOOST_CHECK_MESSAGE( flashes == 0,
95 "Edge_Cuts gerber unexpectedly contains " << flashes << " drill-mark flash(es) (#24416)" );
96}
97
98// Regression for #24867: plotting Edge_Cuts alone to SVG with Actual Size drill
99// marks must still emit the drill marks (the fab drill-map workflow). Same input
100// as NoDrillFlashesOnEdgeCuts above, but the opposite outcome is expected because
101// SVG is a documentation format, not fab output.
102BOOST_AUTO_TEST_CASE( DrillMarksPlottedOnEdgeCutsSvg )
103{
104 const int padDia = pcbIUScale.mmToIU( 1.4 );
105 const int drill = pcbIUScale.mmToIU( 0.8 );
106
107 BOARD board;
108 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( &board );
109 footprint->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 50.0 ), pcbIUScale.mmToIU( 50.0 ) ) );
110
111 PAD* pad = new PAD( footprint.get() );
112 pad->SetPadstackMode( PADSTACK::MODE::NORMAL );
113 pad->SetAttribute( PAD_ATTRIB::PTH );
115 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( padDia, padDia ) );
116 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
117 pad->SetDrillSize( VECTOR2I( drill, drill ) );
118 pad->SetLayerSet( LSET::AllCuMask() | LSET( { F_Mask, B_Mask } ) ); // THT pad: NOT on Edge_Cuts
119 pad->SetPosition( footprint->GetPosition() );
120 footprint->Add( pad );
121 board.Add( footprint.release() );
122
123 SVG_PLOTTER plotter;
124 SIMPLE_RENDER_SETTINGS renderSettings;
125 plotter.SetRenderSettings( &renderSettings );
126
127 wxString svgPath = wxFileName::CreateTempFileName( wxT( "kicad_svg_24867" ) );
128 BOOST_REQUIRE( !svgPath.IsEmpty() );
129 BOOST_REQUIRE( plotter.OpenFile( svgPath ) );
130 plotter.SetViewport( VECTOR2I( 0, 0 ), pcbIUScale.IU_PER_MILS / 10, 1.0, false );
131 BOOST_REQUIRE( plotter.StartPlot( wxT( "1" ) ) );
132
133 PCB_PLOT_PARAMS plotOpts;
134 plotOpts.SetFormat( PLOT_FORMAT::SVG );
135 plotOpts.SetDrillMarksType( DRILL_MARKS::FULL_DRILL_SHAPE ); // Actual Size
136
137 PlotBoardLayers( &board, &plotter, LSEQ{ Edge_Cuts }, plotOpts );
138 BOOST_REQUIRE( plotter.EndPlot() );
139
140 wxFFile file( svgPath, wxT( "rb" ) );
141 BOOST_REQUIRE( file.IsOpened() );
142 wxString contents;
143 BOOST_REQUIRE( file.ReadAll( &contents ) );
144 file.Close();
145 wxRemoveFile( svgPath );
146
147 std::string buf = contents.ToStdString();
148 std::regex circleRe( R"(<circle\b)" ); // the drill mark is the only circle on Edge_Cuts
149 long circles = std::distance( std::sregex_iterator( buf.begin(), buf.end(), circleRe ), std::sregex_iterator() );
150
151 BOOST_CHECK_MESSAGE( circles >= 1, "Edge_Cuts SVG is missing the drill-mark circle (#24867)" );
152}
153
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1497
virtual void SetViewport(const VECTOR2I &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the plot offset and scaling for the current plot.
virtual bool EndPlot() override
virtual bool StartPlot(const wxString &pageNumber) override
Write GERBER header to file initialize global variable g_Plot_PlotOutputFile.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
Definition pad.h:61
Parameters and options when plotting/printing a board.
void SetDrillMarksType(DRILL_MARKS aVal)
void SetFormat(PLOT_FORMAT aFormat)
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition plotter.cpp:75
void SetRenderSettings(RENDER_SETTINGS *aSettings)
Definition plotter.h:166
Minimal concrete render settings suitable for plotters in tests.
virtual bool StartPlot(const wxString &aPageNumber) override
Create SVG file header.
virtual void SetViewport(const VECTOR2I &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the plot offset and scaling for the current plot.
virtual bool EndPlot() override
@ Edge_Cuts
Definition layer_ids.h:108
@ B_Mask
Definition layer_ids.h:94
@ F_Mask
Definition layer_ids.h:93
@ PTH
Plated through hole pad.
Definition padstack.h:97
void PlotBoardLayers(BOARD *aBoard, PLOTTER *aPlotter, const LSEQ &aLayerSequence, const PCB_PLOT_PARAMS &aPlotOptions)
Plot a sequence of board layer IDs.
Plotting engines similar to ps (PostScript, Gerber, svg)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(NoDrillFlashesOnEdgeCuts)
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683