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
74 const BOARD* board = GetBoard();
75
76 SetLayer( board ? board->FlipLayer( GetLayer() ) : ::FlipLayer( GetLayer() ) );
77
78}
79
80
82{
83 m_symbolSize = std::max( aSize, 1 );
84}
85
86
88{
89 const BOARD* board = GetBoard();
90 const int width = board ? board->GetDesignSettings().GetDrillSymbolProfile().GetSymbolWidth() : 0;
91
92 // Numeric marks can reach three character sizes either side of their hole.
93 return 3 * m_symbolSize + 2 * width;
94}
95
96
98{
99 BOX2I box;
100
101 if( const BOARD* board = GetBoard() )
102 {
103 // Holes and the board outline together, so dragging the map snaps against the edge
104 // cuts rather than against whatever hole happens to be outermost
105 box = board->DrillSymbolCache()->m_HoleExtent;
106 box.Inflate( GetSymbolExtent() );
107 box.Merge( board->GetBoardEdgesBoundingBox() );
108 }
109
110 box.Move( m_offset );
111
112 return box;
113}
114
115
116std::shared_ptr<const SHAPE_POLY_SET> PCB_DRILL_MAP::GetBoardOutlines() const
117{
118 std::lock_guard<std::mutex> lock( m_outlineCacheMutex );
119
120 const BOARD* board = GetBoard();
121
122 if( !board )
123 return std::make_shared<const SHAPE_POLY_SET>();
124
125 const uint64_t generation = board->GetBoardOutlineGeneration();
126
128 return m_outlineCache;
129
130 std::shared_ptr<SHAPE_POLY_SET> rebuilt = std::make_shared<SHAPE_POLY_SET>();
131
132 if( const_cast<BOARD*>( board )->GetBoardPolygonOutlines( *rebuilt, false ) )
133 rebuilt->Move( m_offset );
134 else
135 rebuilt->RemoveAllContours();
136
137 m_outlineCache = rebuilt;
138 m_outlineCacheGeneration = generation;
140
141 return m_outlineCache;
142}
143
144
145void RefreshDrillMapOutlines( const BOARD& aBoard, KIGFX::VIEW* aView )
146{
147 if( !aView )
148 return;
149
150 for( const BOARD_ITEM* item : aBoard.Drawings() )
151 {
152 if( item->Type() == PCB_DRILL_MAP_T )
153 aView->Update( item, KIGFX::GEOMETRY | KIGFX::REPAINT );
154 }
155}
156
157
158bool PCB_DRILL_MAP::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
159{
160 const BOARD* board = GetBoard();
161
162 if( !board )
163 return false;
164
165 // Only the marks are clickable. The bounding box spans the whole board, so treating it as
166 // the hit area would make the map answer for every click on the design.
167 const VECTOR2I where = aPosition - m_offset;
168 const int reach = GetSymbolExtent() / 2 + aAccuracy;
169 const std::shared_ptr<const DRILL_SYMBOL_CACHE> cache = board->DrillSymbolCache();
170
171 for( const auto& [itemId, entries] : cache->m_ByItem )
172 {
173 for( const DRILL_SYMBOL_ENTRY& entry : entries )
174 {
175 if( !m_allSpans && !( entry.m_Span == m_span ) )
176 continue;
177
178 if( std::abs( entry.m_Position.x - where.x ) <= reach
179 && std::abs( entry.m_Position.y - where.y ) <= reach )
180 {
181 return true;
182 }
183 }
184 }
185
186 // The outline is drawn and plotted as the map's own artwork, so a map on a board with an
187 // outline but no holes would otherwise be visible and unselectable
188 return GetBoardOutlines()->PointOnEdge( aPosition, aAccuracy );
189}
190
191
192bool PCB_DRILL_MAP::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
193{
194 BOX2I rect = aRect;
195 rect.Inflate( aAccuracy );
196
197 if( aContained )
198 return rect.Contains( GetBoundingBox() );
199
200 return rect.Intersects( GetBoundingBox() );
201}
202
203
204std::vector<int> PCB_DRILL_MAP::ViewGetLayers() const
205{
206 // Its own layer only. The selection outline is drawn there, in the selected colour, and
207 // the overlay would draw it a second time
208 return { GetLayer() };
209}
210
211
212wxString PCB_DRILL_MAP::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
213{
214 return wxString::Format( _( "Drill Map on %s" ), GetLayerName() );
215}
216
217
218void PCB_DRILL_MAP::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
219{
220 aList.emplace_back( _( "Drill Map" ), wxEmptyString );
221 aList.emplace_back( _( "Layer" ), GetLayerName() );
222 aList.emplace_back( _( "Spans" ), m_allSpans ? _( "All" ) : _( "Single" ) );
223}
224
225
227{
228 wxCHECK_RET( aImage && aImage->Type() == Type(), wxT( "Cannot swap data with invalid map." ) );
229
230 PCB_DRILL_MAP* other = static_cast<PCB_DRILL_MAP*>( aImage );
231
232 std::swap( m_layer, other->m_layer );
233 std::swap( m_isLocked, other->m_isLocked );
234 std::swap( m_offset, other->m_offset );
235 std::swap( m_symbolSize, other->m_symbolSize );
236 std::swap( m_span, other->m_span );
237 std::swap( m_allSpans, other->m_allSpans );
238 std::swap( m_outlineSlots, other->m_outlineSlots );
239 std::swap( m_guideCross, other->m_guideCross );
240}
241
242
243double PCB_DRILL_MAP::Similarity( const BOARD_ITEM& aOther ) const
244{
245 if( aOther.Type() != Type() )
246 return 0.0;
247
248 const PCB_DRILL_MAP& other = static_cast<const PCB_DRILL_MAP&>( aOther );
249
250 return other.GetLayer() == GetLayer() ? 1.0 : 0.5;
251}
252
253
254bool PCB_DRILL_MAP::operator==( const BOARD_ITEM& aOther ) const
255{
256 if( aOther.Type() != Type() )
257 return false;
258
259 const PCB_DRILL_MAP& other = static_cast<const PCB_DRILL_MAP&>( aOther );
260
261 // m_span included. Without it the merge driver treats a retargeted map as unchanged
262 return m_offset == other.m_offset && m_symbolSize == other.m_symbolSize && m_allSpans == other.m_allSpans
263 && m_span == other.m_span
265 && GetLayer() == other.GetLayer();
266}
267
268
269void PCB_DRILL_MAP::Serialize( google::protobuf::Any& aContainer ) const
270{
271 using namespace kiapi::board;
272 types::DrillMap map;
273
274 map.mutable_id()->set_value( m_Uuid.AsStdString() );
276 kiapi::common::PackVector2( *map.mutable_position(), GetPosition() );
277 map.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
278 : kiapi::common::types::LockedState::LS_UNLOCKED );
279
280 map.set_all_spans( m_allSpans );
281
282 types::DrillSpan* span = map.mutable_span();
283 span->set_start_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( m_span.DrillStartLayer() ) );
284 span->set_end_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( m_span.DrillEndLayer() ) );
285 span->set_is_backdrill( m_span.m_IsBackdrill );
286 span->set_is_non_plated( m_span.m_IsNonPlatedFile );
287
288 map.set_outline_slots( m_outlineSlots );
289 map.set_guide_cross( m_guideCross );
290 kiapi::common::PackDistance( *map.mutable_symbol_size(), m_symbolSize );
291
292 aContainer.PackFrom( map );
293}
294
295
296bool PCB_DRILL_MAP::Deserialize( const google::protobuf::Any& aContainer )
297{
298 using namespace kiapi::board;
299 types::DrillMap map;
300
301 if( !aContainer.UnpackTo( &map ) )
302 {
303 return false;
304 }
305
306 const PCB_LAYER_ID layer = FromProtoEnum<PCB_LAYER_ID>( map.layer() );
307
308 // Copper, silkscreen, mask, paste, adhesive, Edge.Cuts, Margin and courtyard are all
309 // manufacturing inputs that hole symbols would corrupt rather than document
310 if( !DrillDocumentationLayers().Contains( layer ) )
311 {
312 return false;
313 }
314
315 SetUuidDirect( KIID( map.id().value() ) );
316 SetLayer( layer );
317 SetPosition( kiapi::common::UnpackVector2( map.position() ) );
318 SetLocked( map.locked() == kiapi::common::types::LockedState::LS_LOCKED );
319
320 m_allSpans = map.all_spans();
321
322 if( map.has_span() )
323 {
324 m_span = DRILL_SPAN( FromProtoEnum<PCB_LAYER_ID>( map.span().start_layer() ),
325 FromProtoEnum<PCB_LAYER_ID>( map.span().end_layer() ),
326 map.span().is_backdrill(), map.span().is_non_plated() );
327 }
328
329 m_outlineSlots = map.outline_slots();
330 m_guideCross = map.guide_cross();
331
332 if( map.has_symbol_size() && map.symbol_size().value_nm() > 0 )
333 SetSymbolSize( kiapi::common::UnpackDistance( map.symbol_size() ) );
334
335 return true;
336}
337
338
340{
341 if( m_allSpans || !GetBoard() )
342 return -1;
343
344 const std::vector<DRILL_SPAN> spans = EnumerateDrillSpans( *GetBoard() );
345 const auto it = std::find( spans.begin(), spans.end(), m_span );
346
347 // A span the stackup no longer has reads as every span rather than as an empty map
348 if( it == spans.end() )
349 return -1;
350
351 return static_cast<int>( it - spans.begin() );
352}
353
354
356{
357 if( aIndex < 0 || !GetBoard() )
358 {
359 m_allSpans = true;
360 return;
361 }
362
363 const std::vector<DRILL_SPAN> spans = EnumerateDrillSpans( *GetBoard() );
364
365 if( aIndex >= static_cast<int>( spans.size() ) )
366 {
367 m_allSpans = true;
368 return;
369 }
370
371 m_allSpans = false;
372 m_span = spans[aIndex];
373}
374
375
377{
379 {
382
385
386 const wxString mapProps = _( "Drill Map Properties" );
387
388 // Relative, not absolute. This is how far the marks are slid from their holes, so the
389 // drawing origin has nothing to say about it
390 propMgr.AddProperty( new PROPERTY<PCB_DRILL_MAP, int>( _HKI( "Offset X" ),
393 mapProps );
394
395 propMgr.AddProperty( new PROPERTY<PCB_DRILL_MAP, int>( _HKI( "Offset Y" ),
398 mapProps );
399
400 propMgr.AddProperty( new PROPERTY<PCB_DRILL_MAP, int>( _HKI( "Symbol Size" ),
403 mapProps );
404
405 propMgr.Mask( TYPE_HASH( PCB_DRILL_MAP ), TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ) );
406 propMgr.Mask( TYPE_HASH( PCB_DRILL_MAP ), TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ) );
407
408 // Choices come from the board's stackup, so they are filled in by the properties panel
409 propMgr.AddProperty( new PROPERTY_ENUM<PCB_DRILL_MAP, int>( _HKI( "Hole Span" ),
411 mapProps );
412
413 propMgr.AddProperty( new PROPERTY<PCB_DRILL_MAP, bool>( _HKI( "Outline Slots" ),
415 mapProps );
416
417 propMgr.AddProperty( new PROPERTY<PCB_DRILL_MAP, bool>( _HKI( "Guide Cross" ),
419 mapProps );
420 }
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:927
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:84
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:86
friend class BOARD
Definition board_item.h:578
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:417
PCB_LAYER_ID m_layer
Definition board_item.h:571
bool m_isLocked
Definition board_item.h:573
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:374
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:409
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:1124
std::shared_ptr< const DRILL_SYMBOL_CACHE > DrillSymbolCache() const
Resolved drill symbols, by group and by owning item.
Definition board.cpp:260
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1299
uint64_t GetBoardOutlineGeneration() const
Bumped by every UpdateBoardOutline(), so anything deriving geometry from the edge cuts can tell wheth...
Definition board.h:486
const DRAWINGS & Drawings() const
Definition board.h:465
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:653
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:597
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:63
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:1852
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.Helper macro to map type hashes to names.
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)
Every drill span present on the board, through-holes first.
LSET DrillDocumentationLayers()
Layers a chart or map may live on.
#define _(s)
Some functions to handle hotkeys in KiCad.
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:179
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:411
#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)
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)
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:683