KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drc_creepage_issue23576.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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
34
37
38#include <board.h>
40#include <drc/drc_item.h>
41#include <drc/drc_engine.h>
42#include <footprint.h>
43#include <pcb_marker.h>
44#include <pcb_track.h>
45#include <pad.h>
48
49
51{
53
55 {
56 if( m_board && m_board->GetDesignSettings().m_DRCEngine )
57 m_board->GetDesignSettings().m_DRCEngine->ClearViolationHandler();
58
59 if( m_board )
60 {
61 m_board->SetProject( nullptr );
62 m_board = nullptr;
63 }
64 }
65
67 std::unique_ptr<BOARD> m_board;
68};
69
70
71BOOST_FIXTURE_TEST_CASE( CreepagePathStartPointIssue23576, DRC_CREEPAGE_PATH_FIXTURE )
72{
73 KI_TEST::LoadBoard( m_settingsManager, "issue23389/issue23389", m_board );
74
75 BOOST_REQUIRE_MESSAGE( m_board, "Failed to load board issue23389" );
76
77 struct ViolationInfo
78 {
79 std::shared_ptr<DRC_ITEM> item;
80 VECTOR2I pos;
81 std::vector<PCB_SHAPE> pathShapes;
82 };
83
84 std::vector<ViolationInfo> violations;
85 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
86
87 BOOST_REQUIRE_MESSAGE( bds.m_DRCEngine, "DRC engine not initialized" );
88
89 for( int ii = DRCE_FIRST; ii <= DRCE_LAST; ++ii )
91
93
95 [&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
96 const std::function<void( PCB_MARKER* )>& aPathGenerator )
97 {
98 if( bds.GetSeverity( aItem->GetErrorCode() ) != SEVERITY::RPT_SEVERITY_ERROR )
99 return;
100
101 ViolationInfo vi;
102 vi.item = aItem;
103 vi.pos = aPos;
104
105 if( aPathGenerator )
106 {
107 PCB_MARKER marker( aItem, aPos, aLayer );
108 aPathGenerator( &marker );
109 vi.pathShapes = marker.GetShapes();
110 }
111
112 violations.push_back( vi );
113 } );
114
115 bds.m_DRCEngine->RunTests( EDA_UNITS::MM, true, false );
116
118
119 BOOST_REQUIRE_GE( violations.size(), 1u );
120
121 // Build a lookup of board items by UUID for resolving DRC item references
122 std::map<KIID, BOARD_ITEM*> itemMap;
123
124 for( PCB_TRACK* track : m_board->Tracks() )
125 itemMap[track->m_Uuid] = track;
126
127 for( FOOTPRINT* fp : m_board->Footprints() )
128 {
129 itemMap[fp->m_Uuid] = fp;
130
131 for( PAD* pad : fp->Pads() )
132 itemMap[pad->m_Uuid] = pad;
133 }
134
135 for( size_t i = 0; i < violations.size(); i++ )
136 {
137 const ViolationInfo& vi = violations[i];
138
139 BOOST_TEST_MESSAGE( wxString::Format( "Violation %zu: %s", i,
140 vi.item->GetErrorMessage( false ) ) );
141 BOOST_TEST_MESSAGE( wxString::Format( " Pos: (%.4f, %.4f) mm, shapes: %d",
142 vi.pos.x / 1e6, vi.pos.y / 1e6,
143 (int) vi.pathShapes.size() ) );
144
145 for( size_t j = 0; j < vi.pathShapes.size(); j++ )
146 {
147 const PCB_SHAPE& s = vi.pathShapes[j];
148
149 if( s.GetShape() == SHAPE_T::SEGMENT )
150 {
151 BOOST_TEST_MESSAGE( wxString::Format(
152 " [%zu] SEG: (%.4f,%.4f)->(%.4f,%.4f) mm", j,
153 s.GetStart().x / 1e6, s.GetStart().y / 1e6,
154 s.GetEnd().x / 1e6, s.GetEnd().y / 1e6 ) );
155 }
156 else if( s.GetShape() == SHAPE_T::ARC )
157 {
158 BOOST_TEST_MESSAGE( wxString::Format(
159 " [%zu] ARC: (%.4f,%.4f)->(%.4f,%.4f) c=(%.4f,%.4f) mm", j,
160 s.GetStart().x / 1e6, s.GetStart().y / 1e6,
161 s.GetEnd().x / 1e6, s.GetEnd().y / 1e6,
162 s.GetCenter().x / 1e6, s.GetCenter().y / 1e6 ) );
163 }
164 }
165
166 if( vi.pathShapes.empty() )
167 continue;
168
169 // Resolve the items from the violation
170 BOARD_ITEM* itemA = nullptr;
171 BOARD_ITEM* itemB = nullptr;
172
173 KIID idA = vi.item->GetMainItemID();
174 KIID idB = vi.item->GetAuxItemID();
175
176 auto itA = itemMap.find( idA );
177 auto itB = itemMap.find( idB );
178
179 if( itA != itemMap.end() )
180 itemA = itA->second;
181
182 if( itB != itemMap.end() )
183 itemB = itB->second;
184
185 if( itemA )
186 {
187 BOOST_TEST_MESSAGE( wxString::Format( " ItemA: %s at (%.4f, %.4f) mm",
188 itemA->GetClass(),
189 itemA->GetPosition().x / 1e6, itemA->GetPosition().y / 1e6 ) );
190 }
191
192 if( itemB )
193 {
194 BOOST_TEST_MESSAGE( wxString::Format( " ItemB: %s at (%.4f, %.4f) mm",
195 itemB->GetClass(),
196 itemB->GetPosition().x / 1e6, itemB->GetPosition().y / 1e6 ) );
197 }
198
199 // For tracks, verify that the path shape vertex nearest to the track lies on
200 // its physical edge (at halfWidth from the centerline), not on the centerline.
201 // Path shapes can have inconsistent direction, so check ALL vertices.
202 for( const BOARD_ITEM* item : { itemA, itemB } )
203 {
204 if( !item || item->Type() != PCB_TRACE_T )
205 continue;
206
207 const PCB_TRACK* track = static_cast<const PCB_TRACK*>( item );
208 SEG trackSeg( track->GetStart(), track->GetEnd() );
209 int halfWidth = track->GetWidth() / 2;
210
211 int minDist = std::numeric_limits<int>::max();
212
213 for( const PCB_SHAPE& s : vi.pathShapes )
214 {
215 minDist = std::min( minDist, trackSeg.Distance( s.GetStart() ) );
216 minDist = std::min( minDist, trackSeg.Distance( s.GetEnd() ) );
217 }
218
219 BOOST_TEST_MESSAGE( wxString::Format(
220 " Track hw=%d closest_vertex=%d start=(%.4f,%.4f) end=(%.4f,%.4f)",
221 halfWidth, minDist,
222 track->GetStart().x / 1e6, track->GetStart().y / 1e6,
223 track->GetEnd().x / 1e6, track->GetEnd().y / 1e6 ) );
224
225 int tolerance = 10000; // 10um
226
228 std::abs( minDist - halfWidth ) <= tolerance,
229 wxString::Format(
230 "Violation %zu: closest path vertex is %d nm from track "
231 "centerline, expected %d nm (halfWidth +/- %d nm tolerance). "
232 "Path may be starting at track center instead of edge.",
233 i, minDist, halfWidth, tolerance ) );
234 }
235 }
236}
Container for design settings for a BOARD object.
std::map< int, SEVERITY > m_DRCSeverities
std::shared_ptr< DRC_ENGINE > m_DRCEngine
SEVERITY GetSeverity(int aDRCErrorCode)
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
void RunTests(EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aTestFootprints, BOARD_COMMIT *aCommit=nullptr)
Run the DRC tests.
void SetViolationHandler(DRC_VIOLATION_HANDLER aHandler)
Set an optional DRC violation handler (receives DRC_ITEMs and positions).
Definition drc_engine.h:168
void ClearViolationHandler()
Definition drc_engine.h:173
virtual VECTOR2I GetPosition() const
Definition eda_item.h:279
SHAPE_T GetShape() const
Definition eda_shape.h:181
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:228
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:186
virtual wxString GetClass() const =0
Return the class name.
Definition kiid.h:48
Definition pad.h:55
std::vector< PCB_SHAPE > GetShapes() const
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:81
const VECTOR2I & GetStart() const
Definition pcb_track.h:97
const VECTOR2I & GetEnd() const
Definition pcb_track.h:94
virtual int GetWidth() const
Definition pcb_track.h:91
Definition seg.h:42
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition seg.cpp:702
@ DRCE_CREEPAGE
Definition drc_item.h:45
@ DRCE_FIRST
Definition drc_item.h:39
@ DRCE_LAST
Definition drc_item.h:122
@ SEGMENT
Definition eda_shape.h:47
void LoadBoard(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< BOARD > &aBoard)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_IGNORE
DRC_CREEPAGE_PATH_FIXTURE()=default
BOOST_FIXTURE_TEST_CASE(CreepagePathStartPointIssue23576, DRC_CREEPAGE_PATH_FIXTURE)
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
BOOST_TEST_MESSAGE("\n=== Real-World Polygon PIP Benchmark ===\n"<< formatTable(table))
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:93
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687