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 auto footprint = std::make_unique<FOOTPRINT>( &board );
52 footprint->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 50.0 ), pcbIUScale.mmToIU( 50.0 ) ) );
53
54 auto pad = new PAD( footprint.get() );
55 pad->SetAttribute( PAD_ATTRIB::PTH );
57 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( padDia, padDia ) );
58 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
59 pad->SetDrillSize( VECTOR2I( drill, drill ) );
60 pad->SetLayerSet( LSET::AllCuMask() | LSET( { F_Mask, B_Mask } ) ); // THT pad: NOT on Edge_Cuts
61 pad->SetPosition( footprint->GetPosition() );
62 footprint->Add( pad );
63 board.Add( footprint.release() );
64
65 GERBER_PLOTTER plotter;
66 SIMPLE_RENDER_SETTINGS renderSettings;
67 plotter.SetRenderSettings( &renderSettings );
68
69 wxString gbrPath = wxFileName::CreateTempFileName( wxT( "kicad_gbr_24416" ) );
70 BOOST_REQUIRE( !gbrPath.IsEmpty() );
71 BOOST_REQUIRE( plotter.OpenFile( gbrPath ) );
72 plotter.SetViewport( VECTOR2I( 0, 0 ), pcbIUScale.IU_PER_MILS / 10, 1.0, false );
73 BOOST_REQUIRE( plotter.StartPlot( wxT( "1" ) ) );
74
75 PCB_PLOT_PARAMS plotOpts;
77 plotOpts.SetDrillMarksType( DRILL_MARKS::FULL_DRILL_SHAPE ); // triggers PlotDrillMarks()
78
79 PlotBoardLayers( &board, &plotter, LSEQ{ Edge_Cuts }, plotOpts );
80 BOOST_REQUIRE( plotter.EndPlot() );
81
82 wxFFile file( gbrPath, wxT( "rb" ) );
83 BOOST_REQUIRE( file.IsOpened() );
84 wxString contents;
85 BOOST_REQUIRE( file.ReadAll( &contents ) );
86 file.Close();
87 wxRemoveFile( gbrPath );
88
89 std::string buf = contents.ToStdString();
90 std::regex flashRe( R"(D0*3\*)" ); // D03 = flash a pad/aperture
91 long flashes = std::distance( std::sregex_iterator( buf.begin(), buf.end(), flashRe ), std::sregex_iterator() );
92
93 BOOST_CHECK_MESSAGE( flashes == 0,
94 "Edge_Cuts gerber unexpectedly contains " << flashes << " drill-mark flash(es) (#24416)" );
95}
96
97// Regression for #24867: plotting Edge_Cuts alone to SVG with Actual Size drill
98// marks must still emit the drill marks (the fab drill-map workflow). Same input
99// as NoDrillFlashesOnEdgeCuts above, but the opposite outcome is expected because
100// SVG is a documentation format, not fab output.
101BOOST_AUTO_TEST_CASE( DrillMarksPlottedOnEdgeCutsSvg )
102{
103 const int padDia = pcbIUScale.mmToIU( 1.4 );
104 const int drill = pcbIUScale.mmToIU( 0.8 );
105
106 BOARD board;
107 auto footprint = std::make_unique<FOOTPRINT>( &board );
108 footprint->SetPosition( VECTOR2I( pcbIUScale.mmToIU( 50.0 ), pcbIUScale.mmToIU( 50.0 ) ) );
109
110 auto pad = new PAD( footprint.get() );
111 pad->SetAttribute( PAD_ATTRIB::PTH );
113 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( padDia, padDia ) );
114 pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
115 pad->SetDrillSize( VECTOR2I( drill, drill ) );
116 pad->SetLayerSet( LSET::AllCuMask() | LSET( { F_Mask, B_Mask } ) ); // THT pad: NOT on Edge_Cuts
117 pad->SetPosition( footprint->GetPosition() );
118 footprint->Add( pad );
119 board.Add( footprint.release() );
120
121 SVG_PLOTTER plotter;
122 SIMPLE_RENDER_SETTINGS renderSettings;
123 plotter.SetRenderSettings( &renderSettings );
124
125 wxString svgPath = wxFileName::CreateTempFileName( wxT( "kicad_svg_24867" ) );
126 BOOST_REQUIRE( !svgPath.IsEmpty() );
127 BOOST_REQUIRE( plotter.OpenFile( svgPath ) );
128 plotter.SetViewport( VECTOR2I( 0, 0 ), pcbIUScale.IU_PER_MILS / 10, 1.0, false );
129 BOOST_REQUIRE( plotter.StartPlot( wxT( "1" ) ) );
130
131 PCB_PLOT_PARAMS plotOpts;
132 plotOpts.SetFormat( PLOT_FORMAT::SVG );
133 plotOpts.SetDrillMarksType( DRILL_MARKS::FULL_DRILL_SHAPE ); // Actual Size
134
135 PlotBoardLayers( &board, &plotter, LSEQ{ Edge_Cuts }, plotOpts );
136 BOOST_REQUIRE( plotter.EndPlot() );
137
138 wxFFile file( svgPath, wxT( "rb" ) );
139 BOOST_REQUIRE( file.IsOpened() );
140 wxString contents;
141 BOOST_REQUIRE( file.ReadAll( &contents ) );
142 file.Close();
143 wxRemoveFile( svgPath );
144
145 std::string buf = contents.ToStdString();
146 std::regex circleRe( R"(<circle\b)" ); // the drill mark is the only circle on Edge_Cuts
147 long circles = std::distance( std::sregex_iterator( buf.begin(), buf.end(), circleRe ), std::sregex_iterator() );
148
149 BOOST_CHECK_MESSAGE( circles >= 1, "Edge_Cuts SVG is missing the drill-mark circle (#24867)" );
150}
151
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:373
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1355
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
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
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:73
void SetRenderSettings(RENDER_SETTINGS *aSettings)
Definition plotter.h:163
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:98
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