KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_drill_map.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
20#include <pcb_drill_map.h>
21
22#include <api/api_enums.h>
23#include <api/api_utils.h>
24#include <api/board/board_types.pb.h>
25
26#include <base_units.h>
27#include <board.h>
31#include <i18n_utility.h>
33#include <view/view.h>
34#include <widgets/msgpanel.h>
35
36
38 BOARD_ITEM( aParent, PCB_DRILL_MAP_T ),
40 m_allSpans( true ),
41 m_outlineSlots( true ),
42 m_guideCross( false ),
44{
45 if( BOARD* board = GetBoard() )
46 m_symbolSize = board->GetDesignSettings().GetDrillSymbolProfile().GetSymbolSize();
47}
48
49
51 BOARD_ITEM( aOther ),
52 m_offset( aOther.m_offset ),
53 m_symbolSize( aOther.m_symbolSize ),
54 m_span( aOther.m_span ),
55 m_allSpans( aOther.m_allSpans ),
57 m_guideCross( aOther.m_guideCross ),
59{
60}
61
62
63void PCB_DRILL_MAP::Rotate( const VECTOR2I& aCentre, const EDA_ANGLE& aAngle )
64{
65 // The marks sit at their own holes and the offset is a displacement from each one, so
66 // there is no geometry here to turn
67}
68
69
70void PCB_DRILL_MAP::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aDirection )
71{
72 // The offset is a displacement of every mark from its own hole, so there is nothing to
73 // mirror. The side the map documents is still the side it belongs on
75}
76
77
79{
80 m_symbolSize = std::max( aSize, 1 );
81}
82
83
85{
86 const BOARD* board = GetBoard();
87 const int width = board ? board->GetDesignSettings().GetDrillSymbolProfile().GetSymbolWidth() : 0;
88
89 // Numeric marks can reach three character sizes either side of their hole.
90 return 3 * m_symbolSize + 2 * width;
91}
92
93
95{
96 BOX2I box;
97
98 if( const BOARD* board = GetBoard() )
99 {
100 // Holes and the board outline together, so dragging the map snaps against the edge
101 // cuts rather than against whatever hole happens to be outermost
102 box = board->DrillSymbolCache()->m_HoleExtent;
103 box.Inflate( GetSymbolExtent() );
104 box.Merge( board->GetBoardEdgesBoundingBox() );
105 }
106
107 box.Move( m_offset );
108
109 return box;
110}
111
112
113std::shared_ptr<const SHAPE_POLY_SET> PCB_DRILL_MAP::GetBoardOutlines() const
114{
115 std::lock_guard<std::mutex> lock( m_outlineCacheMutex );
116
117 const BOARD* board = GetBoard();
118
119 if( !board )
120 return std::make_shared<const SHAPE_POLY_SET>();
121
122 const uint64_t generation = board->GetBoardOutlineGeneration();
123
125 return m_outlineCache;
126
127 std::shared_ptr<SHAPE_POLY_SET> rebuilt = std::make_shared<SHAPE_POLY_SET>();
128
129 if( const_cast<BOARD*>( board )->GetBoardPolygonOutlines( *rebuilt, false ) )
130 rebuilt->Move( m_offset );
131 else
132 rebuilt->RemoveAllContours();
133
134 m_outlineCache = rebuilt;
135 m_outlineCacheGeneration = generation;
137
138 return m_outlineCache;
139}
140
141
142void RefreshDrillMapOutlines( const BOARD& aBoard, KIGFX::VIEW* aView )
143{
144 if( !aView )
145 return;
146
147 for( const BOARD_ITEM* item : aBoard.Drawings() )
148 {
149 if( item->Type() == PCB_DRILL_MAP_T )
150 aView->Update( item, KIGFX::GEOMETRY | KIGFX::REPAINT );
151 }
152}
153
154
155bool PCB_DRILL_MAP::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
156{
157 const BOARD* board = GetBoard();
158
159 if( !board )
160 return false;
161
162 // Only the marks are clickable. The bounding box spans the whole board, so treating it as
163 // the hit area would make the map answer for every click on the design.
164 const VECTOR2I where = aPosition - m_offset;
165 const int reach = GetSymbolExtent() / 2 + aAccuracy;
166 const std::shared_ptr<const DRILL_SYMBOL_CACHE> cache = board->DrillSymbolCache();
167
168 for( const auto& [itemId, entries] : cache->m_ByItem )
169 {
170 for( const DRILL_SYMBOL_ENTRY& entry : entries )
171 {
172 if( !m_allSpans && !( entry.m_Span == m_span ) )
173 continue;
174
175 if( std::abs( entry.m_Position.x - where.x ) <= reach
176 && std::abs( entry.m_Position.y - where.y ) <= reach )
177 {
178 return true;
179 }
180 }
181 }
182
183 // The outline is drawn and plotted as the map's own artwork, so a map on a board with an
184 // outline but no holes would otherwise be visible and unselectable
185 return GetBoardOutlines()->PointOnEdge( aPosition, aAccuracy );
186}
187
188
189bool PCB_DRILL_MAP::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
190{
191 BOX2I rect = aRect;
192 rect.Inflate( aAccuracy );
193
194 if( aContained )
195 return rect.Contains( GetBoundingBox() );
196
197 return rect.Intersects( GetBoundingBox() );
198}
199
200
201std::vector<int> PCB_DRILL_MAP::ViewGetLayers() const
202{
203 // Its own layer only. The selection outline is drawn there, in the selected colour, and
204 // the overlay would draw it a second time
205 return { GetLayer() };
206}
207
208
209wxString PCB_DRILL_MAP::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
210{
211 return wxString::Format( _( "Drill Map on %s" ), GetLayerName() );
212}
213
214
215void PCB_DRILL_MAP::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
216{
217 aList.emplace_back( _( "Drill Map" ), wxEmptyString );
218 aList.emplace_back( _( "Layer" ), GetLayerName() );
219 aList.emplace_back( _( "Spans" ), m_allSpans ? _( "All" ) : _( "Single" ) );
220}
221
222
224{
225 wxCHECK_RET( aImage && aImage->Type() == Type(), wxT( "Cannot swap data with invalid map." ) );
226
227 PCB_DRILL_MAP* other = static_cast<PCB_DRILL_MAP*>( aImage );
228
229 std::swap( m_layer, other->m_layer );
230 std::swap( m_isLocked, other->m_isLocked );
231 std::swap( m_offset, other->m_offset );
232 std::swap( m_symbolSize, other->m_symbolSize );
233 std::swap( m_span, other->m_span );
234 std::swap( m_allSpans, other->m_allSpans );
235 std::swap( m_outlineSlots, other->m_outlineSlots );
236 std::swap( m_guideCross, other->m_guideCross );
237}
238
239
240double PCB_DRILL_MAP::Similarity( const BOARD_ITEM& aOther ) const
241{
242 if( aOther.Type() != Type() )
243 return 0.0;
244
245 const PCB_DRILL_MAP& other = static_cast<const PCB_DRILL_MAP&>( aOther );
246
247 return other.GetLayer() == GetLayer() ? 1.0 : 0.5;
248}
249
250
251bool PCB_DRILL_MAP::operator==( const BOARD_ITEM& aOther ) const
252{
253 if( aOther.Type() != Type() )
254 return false;
255
256 const PCB_DRILL_MAP& other = static_cast<const PCB_DRILL_MAP&>( aOther );
257
258 // m_span included. Without it the merge driver treats a retargeted map as unchanged
259 return m_offset == other.m_offset && m_symbolSize == other.m_symbolSize && m_allSpans == other.m_allSpans
260 && m_span == other.m_span
262 && GetLayer() == other.GetLayer();
263}
264
265
266void PCB_DRILL_MAP::Serialize( google::protobuf::Any& aContainer ) const
267{
268 using namespace kiapi::board;
269 types::DrillMap map;
270
271 map.mutable_id()->set_value( m_Uuid.AsStdString() );
273 kiapi::common::PackVector2( *map.mutable_position(), GetPosition() );
274 map.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
275 : kiapi::common::types::LockedState::LS_UNLOCKED );
276
277 map.set_all_spans( m_allSpans );
278
279 types::DrillSpan* span = map.mutable_span();
280 span->set_start_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( m_span.DrillStartLayer() ) );
281 span->set_end_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( m_span.DrillEndLayer() ) );
282 span->set_is_backdrill( m_span.m_IsBackdrill );
283 span->set_is_non_plated( m_span.m_IsNonPlatedFile );
284
285 map.set_outline_slots( m_outlineSlots );
286 map.set_guide_cross( m_guideCross );
287 kiapi::common::PackDistance( *map.mutable_symbol_size(), m_symbolSize );
288
289 aContainer.PackFrom( map );
290}
291
292
293bool PCB_DRILL_MAP::Deserialize( const google::protobuf::Any& aContainer )
294{
295 using namespace kiapi::board;
296 types::DrillMap map;
297
298 if( !aContainer.UnpackTo( &map ) )
299 {
300 return false;
301 }
302
303 const PCB_LAYER_ID layer = FromProtoEnum<PCB_LAYER_ID>( map.layer() );
304
305 // Copper, silkscreen, mask, paste, adhesive, Edge.Cuts, Margin and courtyard are all
306 // manufacturing inputs that hole symbols would corrupt rather than document
307 if( !DocumentationLayers().Contains( layer ) )
308 {
309 return false;
310 }
311
312 SetUuidDirect( KIID( map.id().value() ) );
313 SetLayer( layer );
314 SetPosition( kiapi::common::UnpackVector2( map.position() ) );
315 SetLocked( map.locked() == kiapi::common::types::LockedState::LS_LOCKED );
316
317 m_allSpans = map.all_spans();
318
319 if( map.has_span() )
320 {
321 m_span = DRILL_SPAN( FromProtoEnum<PCB_LAYER_ID>( map.span().start_layer() ),
322 FromProtoEnum<PCB_LAYER_ID>( map.span().end_layer() ),
323 map.span().is_backdrill(), map.span().is_non_plated() );
324 }
325
326 m_outlineSlots = map.outline_slots();
327 m_guideCross = map.guide_cross();
328
329 if( map.has_symbol_size() && map.symbol_size().value_nm() > 0 )
330 SetSymbolSize( kiapi::common::UnpackDistance( map.symbol_size() ) );
331
332 return true;
333}
334
335
337{
338 if( m_allSpans || !GetBoard() )
339 return -1;
340
341 const std::vector<DRILL_SPAN> spans = EnumerateDrillSpans( *GetBoard() );
342 const auto it = std::find( spans.begin(), spans.end(), m_span );
343
344 // A span the stackup no longer has reads as every span rather than as an empty map
345 if( it == spans.end() )
346 return -1;
347
348 return static_cast<int>( it - spans.begin() );
349}
350
351
353{
354 if( aIndex < 0 || !GetBoard() )
355 {
356 m_allSpans = true;
357 return;
358 }
359
360 const std::vector<DRILL_SPAN> spans = EnumerateDrillSpans( *GetBoard() );
361
362 if( aIndex >= static_cast<int>( spans.size() ) )
363 {
364 m_allSpans = true;
365 return;
366 }
367
368 m_allSpans = false;
369 m_span = spans[aIndex];
370}
371
372
374{
376 {
379
382
383 const wxString mapProps = _( "Drill Map Properties" );
384
385 // Relative, not absolute. This is how far the marks are slid from their holes, so the
386 // drawing origin has nothing to say about it
387 propMgr.AddProperty( new PROPERTY<PCB_DRILL_MAP, int>( _HKI( "Offset X" ),
390 mapProps );
391
392 propMgr.AddProperty( new PROPERTY<PCB_DRILL_MAP, int>( _HKI( "Offset Y" ),
395 mapProps );
396
397 propMgr.AddProperty( new PROPERTY<PCB_DRILL_MAP, int>( _HKI( "Symbol Size" ),
400 mapProps );
401
402 propMgr.Mask( TYPE_HASH( PCB_DRILL_MAP ), TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ) );
403 propMgr.Mask( TYPE_HASH( PCB_DRILL_MAP ), TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ) );
404
405 // Choices come from the board's stackup, so they are filled in by the properties panel
406 propMgr.AddProperty( new PROPERTY_ENUM<PCB_DRILL_MAP, int>( _HKI( "Hole Span" ),
408 mapProps );
409
410 propMgr.AddProperty( new PROPERTY<PCB_DRILL_MAP, bool>( _HKI( "Outline Slots" ),
412 mapProps );
413
414 propMgr.AddProperty( new PROPERTY<PCB_DRILL_MAP, bool>( _HKI( "Guide Cross" ),
416 mapProps );
417 }
KICOMMON_API types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICOMMON_API KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:55
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
DRILL_SYMBOL_PROFILE & GetDrillSymbolProfile()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:85
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:87
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:427
PCB_LAYER_ID GetFlippedLayer(PCB_LAYER_ID aLayer) const
Return the layer paired with aLayer on the opposite side of the board.
PCB_LAYER_ID m_layer
Definition board_item.h:600
bool m_isLocked
Definition board_item.h:602
bool IsLocked() const override
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:383
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:411
std::shared_ptr< const DRILL_SYMBOL_CACHE > DrillSymbolCache() const
Resolved drill symbols, by group and by owning item.
Definition board.cpp:265
uint64_t GetBoardOutlineGeneration() const
Bumped by every UpdateBoardOutline(), so anything deriving geometry from the edge cuts can tell wheth...
Definition board.h:495
BOARD_DESIGN_SETTINGS & GetDesignSettings()
Definition board.cpp:1290
const DRAWINGS & Drawings() const
Definition board.h:467
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition box2.h:135
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
Grouping rules and symbol assignments, shared by reference so a chart and its map can never disagree ...
The base class for create windows for drawing purpose.
const KIID m_Uuid
Definition eda_item.h:599
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:68
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition view.cpp:2631
Definition kiid.h:46
Turns on drill symbols at the holes, for one layer.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
int GetOffsetX() const
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
std::shared_ptr< const SHAPE_POLY_SET > m_outlineCache
void SetSpanChoice(int aIndex)
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
VECTOR2I m_outlineCacheOffset
std::mutex m_outlineCacheMutex
int GetSymbolSize() const
void SetOffsetY(int aY)
bool GetGuideCross() const
void SetGuideCross(bool aOn)
void SetSymbolSize(int aSize)
VECTOR2I GetPosition() const override
The map has no place of its own.
void swapData(BOARD_ITEM *aImage) override
uint64_t m_outlineCacheGeneration
bool GetOutlineSlots() const
void SetOutlineSlots(bool aOn)
void SetOffsetX(int aX)
bool operator==(const BOARD_ITEM &aOther) const override
VECTOR2I m_offset
int GetSymbolExtent() const
void Rotate(const VECTOR2I &aCentre, const EDA_ANGLE &aAngle) override
Configuration operations, deliberately not geometry transforms.
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
DRILL_SPAN m_span
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
std::shared_ptr< const SHAPE_POLY_SET > GetBoardOutlines() const
The board outline displaced by this map's offset.
double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
int GetOffsetY() const
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
PCB_DRILL_MAP(BOARD_ITEM *aParent)
void SetPosition(const VECTOR2I &aPos) override
int GetSpanChoice() const
The span as an index into the board's spans, with -1 for every span.
Provide class metadata.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
bool PointOnEdge(const VECTOR2I &aP, int aAccuracy=0) const
Check if point aP lies on an edge or vertex of some of the outlines or holes.
std::vector< DRILL_SPAN > EnumerateDrillSpans(const BOARD &aBoard, bool aPadBackdrills)
Every drill span present on the board, through-holes first.
#define _(s)
LSET DocumentationLayers()
Layers a drill chart or drill map may live on.
Some functions to handle hotkeys in KiCad.
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
FLIP_DIRECTION
Definition mirror.h:23
Message panel definition file.
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:54
@ GEOMETRY
Position or shape has changed.
Definition view_item.h:51
KICOMMON_API int UnpackDistance(const types::Distance &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackDistance(types::Distance &aOutput, int aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput, const EDA_IU_SCALE &aScale)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
#define _HKI(x)
Definition page_info.cpp:40
static struct PCB_DRILL_MAP_DESC _PCB_DRILL_MAP_DESC
void RefreshDrillMapOutlines(const BOARD &aBoard, KIGFX::VIEW *aView)
Repaint every drill map after an Edge.Cuts edit.
#define TYPE_HASH(x)
Macro to generate unique identifier for a type.
Definition property.h:74
@ PT_COORD
Coordinate expressed in distance units (mm/inch)
Definition property.h:65
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
#define REGISTER_TYPE(x)
Helper macro to map type hashes to names.
One drawable mark, with the geometry the renderer needs to place it.
@ PCB_DRILL_MAP_T
class PCB_DRILL_MAP, drill symbols drawn at the holes
Definition typeinfo.h:240
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708