1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
5  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
23  */
24 
25 /**
26  * @brief A single base class (PCB_TRACK) represents both tracks and vias, with subclasses
27  * for curved tracks (PCB_ARC) and vias (PCB_VIA).  All told there are three KICAD_Ts:
28  * PCB_TRACK_T, PCB_ARC_T, and PCB_VIA_T.
29  *
30  * For vias there is a further VIATYPE which indicates THROUGH, BLIND_BURIED, or
31  * MICROVIA, which are supported by the synthetic KICAD_Ts PCB_LOCATE_STDVIA_T,
32  * PCB_LOCATE_BBVIA_T, and PCB_LOCATE_UVIA_T.
33  */
34 
35 #ifndef CLASS_TRACK_H
36 #define CLASS_TRACK_H
37 
38 
39 #include <board_connected_item.h>
40 #include <convert_to_biu.h>
41 
42 
43 class PCB_TRACK;
44 class PCB_VIA;
45 class PAD;
46 class MSG_PANEL_ITEM;
47 class SHAPE_POLY_SET;
48 class SHAPE_ARC;
49 
50 
51 // Flag used in locate routines (from which endpoint work)
52 enum ENDPOINT_T : int
53 {
54     ENDPOINT_START = 0,
55     ENDPOINT_END = 1
56 };
57 
58 // Via types
59 // Note that this enum must be synchronized to GAL_LAYER_ID
60 enum class VIATYPE : int
61 {
62     THROUGH      = 3, /* Always a through hole via */
63     BLIND_BURIED = 2, /* this via can be on internal layers */
64     MICROVIA     = 1, /* this via which connect from an external layer
65                                 * to the near neighbor internal layer */
66     NOT_DEFINED  = 0  /* not yet used */
67 };
68 
69 #define UNDEFINED_DRILL_DIAMETER  -1       //< Undefined via drill diameter.
70 
71 // Used for tracks and vias for algorithmic safety, not to enforce constraints
72 #define GEOMETRY_MIN_SIZE ( int )( 0.001 * IU_PER_MM )
73 
74 
75 class PCB_TRACK : public BOARD_CONNECTED_ITEM
76 {
77 public:
ClassOf(const EDA_ITEM * aItem)78     static inline bool ClassOf( const EDA_ITEM* aItem )
79     {
80         return aItem && PCB_TRACE_T == aItem->Type();
81     }
82 
83     PCB_TRACK( BOARD_ITEM* aParent, KICAD_T idtype = PCB_TRACE_T );
84 
85     // Do not create a copy constructor.  The one generated by the compiler is adequate.
86 
Move(const wxPoint & aMoveVector)87     void Move( const wxPoint& aMoveVector ) override
88     {
89         m_Start += aMoveVector;
90         m_End   += aMoveVector;
91     }
92 
93     void Rotate( const wxPoint& aRotCentre, double aAngle ) override;
94 
95     void Flip( const wxPoint& aCentre, bool aFlipLeftRight ) override;
96 
SetPosition(const wxPoint & aPos)97     void SetPosition( const wxPoint& aPos ) override { m_Start = aPos; }
GetPosition()98     wxPoint GetPosition() const override { return m_Start; }
GetFocusPosition()99     const wxPoint GetFocusPosition() const override { return ( m_Start + m_End ) / 2; }
100 
SetWidth(int aWidth)101     void SetWidth( int aWidth )                 { m_Width = aWidth; }
GetWidth()102     int GetWidth() const                        { return m_Width; }
103 
SetEnd(const wxPoint & aEnd)104     void SetEnd( const wxPoint& aEnd )          { m_End = aEnd; }
GetEnd()105     const wxPoint& GetEnd() const               { return m_End; }
106 
SetStart(const wxPoint & aStart)107     void SetStart( const wxPoint& aStart )      { m_Start = aStart; }
GetStart()108     const wxPoint& GetStart() const             { return m_Start; }
109 
SetEndX(int aX)110     void SetEndX( int aX ) { m_End.x = aX; }
SetEndY(int aY)111     void SetEndY( int aY ) { m_End.y = aY; }
112 
GetEndX()113     int GetEndX() const { return m_End.x; }
GetEndY()114     int GetEndY() const { return m_End.y; }
115 
116     /// Return the selected endpoint (start or end)
GetEndPoint(ENDPOINT_T aEndPoint)117     const wxPoint& GetEndPoint( ENDPOINT_T aEndPoint ) const
118     {
119         if( aEndPoint == ENDPOINT_START )
120             return m_Start;
121         else
122             return m_End;
123     }
124 
125     // Virtual function
126     const EDA_RECT GetBoundingBox() const override;
127 
128     /**
129      * Function GetLength
130      * returns the length of the track using the hypotenuse calculation.
131      * @return double - the length of the track
132      */
133     virtual double GetLength() const;
134 
135     /**
136      * Function TransformShapeWithClearanceToPolygon
137      * Convert the track shape to a closed polygon
138      * Used in filling zones calculations
139      * Circles (vias) and arcs (ends of tracks) are approximated by segments
140      * @param aCornerBuffer = a buffer to store the polygon
141      * @param aClearanceValue = the clearance around the pad
142      * @param aError = the maximum deviation from true circle
143      * @param ignoreLineWidth = used for edge cut items where the line width is only
144      * for visualization
145      */
146     void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
147                                                PCB_LAYER_ID aLayer, int aClearanceValue,
148                                                int aError, ERROR_LOC aErrorLoc,
149                                                bool ignoreLineWidth = false ) const override;
150 
151     // @copydoc BOARD_ITEM::GetEffectiveShape
152     virtual std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const override;
153 
154     /**
155      * Function IsPointOnEnds
156      * returns STARTPOINT if point if near (dist = min_dist) start point, ENDPOINT if
157      * point if near (dist = min_dist) end point,STARTPOINT|ENDPOINT if point if near
158      * (dist = min_dist) both ends, or 0 if none of the above.
159      * if min_dist < 0: min_dist = track_width/2
160      */
161     EDA_ITEM_FLAGS IsPointOnEnds( const wxPoint& point, int min_dist = 0 ) const;
162 
163     /**
164      * Function IsNull
165      * returns true if segment length is zero.
166      */
IsNull()167     bool IsNull() const
168     {
169         return ( Type() == PCB_VIA_T ) || ( m_Start == m_End );
170     }
171 
172     void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
173 
174     SEARCH_RESULT Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] ) override;
175 
176     bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override;
177     bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override;
178 
179     bool ApproxCollinear( const PCB_TRACK& aTrack );
180 
GetClass()181     wxString GetClass() const override
182     {
183         return wxT( "PCB_TRACK" );
184     }
185 
186     /**
187      * Function GetLocalClearance
188      * returns any local clearance overrides set in the "classic" (ie: pre-rule) system.
189      * @param aSource [out] optionally reports the source as a user-readable string
190      * @return int - the clearance in internal units.
191      */
192     int GetLocalClearance( wxString* aSource ) const override;
193 
194     wxString GetSelectMenuText( EDA_UNITS aUnits ) const override;
195 
196     BITMAPS GetMenuImage() const override;
197 
198     virtual EDA_ITEM* Clone() const override;
199 
200     virtual void ViewGetLayers( int aLayers[], int& aCount ) const override;
201 
202     double ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override;
203 
204     const BOX2I ViewBBox() const override;
205 
206     virtual void SwapData( BOARD_ITEM* aImage ) override;
207 
208     /**
209      * @return true because a track or a via is always on a copper layer.
210      */
IsOnCopperLayer()211     bool IsOnCopperLayer() const override
212     {
213         return true;
214     }
215 
216     struct cmp_tracks
217     {
218         bool operator()( const PCB_TRACK* aFirst, const PCB_TRACK* aSecond ) const;
219     };
220 
221 #if defined (DEBUG)
Show(int nestLevel,std::ostream & os)222     virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
223 
224     /**
225      * Function ShowState
226      * converts a set of state bits to a wxString
227      * @param stateBits Is an OR-ed together set of bits like IN_EDIT, etc.
228      */
229     static wxString ShowState( int stateBits );
230 
231 #endif
232 
233 protected:
234     void GetMsgPanelInfoBase_Common( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) const;
235 
236 
237     int         m_Width;            ///< Thickness of track, or via diameter
238     wxPoint     m_Start;            ///< Line start point
239     wxPoint     m_End;              ///< Line end point
240 
241 };
242 
243 
244 class PCB_ARC : public PCB_TRACK
245 {
246 public:
PCB_ARC(BOARD_ITEM * aParent)247     PCB_ARC( BOARD_ITEM* aParent ) :
248         PCB_TRACK( aParent, PCB_ARC_T )
249     {
250     };
251 
252     PCB_ARC( BOARD_ITEM* aParent, const SHAPE_ARC* aArc );
253 
ClassOf(const EDA_ITEM * aItem)254     static inline bool ClassOf( const EDA_ITEM *aItem )
255     {
256         return aItem && PCB_ARC_T == aItem->Type();
257     }
258 
Move(const wxPoint & aMoveVector)259     virtual void Move( const wxPoint& aMoveVector ) override
260     {
261         m_Start += aMoveVector;
262         m_Mid   += aMoveVector;
263         m_End   += aMoveVector;
264     }
265 
266     virtual void Rotate( const wxPoint& aRotCentre, double aAngle ) override;
267 
268     virtual void Flip( const wxPoint& aCentre, bool aFlipLeftRight ) override;
269 
SetMid(const wxPoint & aMid)270     void SetMid( const wxPoint& aMid )          { m_Mid = aMid; }
GetMid()271     const wxPoint& GetMid() const               { return m_Mid; }
272 
SetPosition(const wxPoint & aPos)273     void SetPosition( const wxPoint& aPos ) override
274     {
275         m_Start = aPos;
276     }
277 
278     virtual wxPoint GetPosition() const override;
279 
GetCenter()280     virtual wxPoint GetCenter() const override { return GetPosition(); }
281 
282     double GetRadius() const;
283     double GetAngle() const;
284     double GetArcAngleStart() const;
285     double GetArcAngleEnd() const;
286     virtual bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override;
287 
288     virtual bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const override;
289 
GetClass()290     wxString GetClass() const override
291     {
292         return wxT( "PCB_ARC" );
293     }
294 
295     // @copydoc BOARD_ITEM::GetEffectiveShape
296     virtual std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const override;
297 
298     //TODO(snh): Add GetSelectMenuText() and GetMsgPanelInfoBase()
299 
300     /**
301      * Function GetLength
302      * returns the length of the arc track
303      * @return double - the length of the track
304      */
GetLength()305     virtual double GetLength() const override
306     {
307         double radius = GetRadius();
308         double includedAngle  = std::abs( GetAngle() );
309 
310         return radius * M_PI * includedAngle / 1800.0;
311     }
312 
313     EDA_ITEM* Clone() const override;
314 
315     virtual void SwapData( BOARD_ITEM* aImage ) override;
316 
317 private:
318     wxPoint     m_Mid;                      ///< Arc mid point, halfway between start and end
319 };
320 
321 
322 class PCB_VIA : public PCB_TRACK
323 {
324 public:
325     PCB_VIA( BOARD_ITEM* aParent );
326 
ClassOf(const EDA_ITEM * aItem)327     static inline bool ClassOf( const EDA_ITEM *aItem )
328     {
329         return aItem && PCB_VIA_T == aItem->Type();
330     }
331 
332     // Do not create a copy constructor.  The one generated by the compiler is adequate.
333 
IsType(const KICAD_T aScanTypes[])334     bool IsType( const KICAD_T aScanTypes[] ) const override
335     {
336         if( BOARD_CONNECTED_ITEM::IsType( aScanTypes ) )
337             return true;
338 
339         for( const KICAD_T* p = aScanTypes; *p != EOT; ++p )
340         {
341             if( *p == PCB_LOCATE_STDVIA_T && m_viaType == VIATYPE::THROUGH )
342                 return true;
343             else if( *p == PCB_LOCATE_UVIA_T && m_viaType == VIATYPE::MICROVIA )
344                 return true;
345             else if( *p == PCB_LOCATE_BBVIA_T && m_viaType == VIATYPE::BLIND_BURIED )
346                 return true;
347         }
348 
349         return false;
350     }
351 
GetViaType()352     VIATYPE GetViaType() const { return m_viaType; }
SetViaType(VIATYPE aViaType)353     void SetViaType( VIATYPE aViaType ) { m_viaType = aViaType; }
354 
355     bool IsOnLayer( PCB_LAYER_ID aLayer ) const override;
356 
357     virtual LSET GetLayerSet() const override;
358     virtual void SetLayerSet( LSET aLayers ) override;
359 
360     /**
361      * Function SetLayerPair
362      * For a via m_layer contains the top layer, the other layer is in m_bottomLayer
363      * @param aTopLayer = first layer connected by the via
364      * @param aBottomLayer = last layer connected by the via
365      */
366     void SetLayerPair( PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer );
367 
368     void SetBottomLayer( PCB_LAYER_ID aLayer );
369     void SetTopLayer( PCB_LAYER_ID aLayer );
370 
371     /**
372      * Function LayerPair
373      * Return the 2 layers used by  the via (the via actually uses
374      * all layers between these 2 layers)
375      *  @param top_layer = pointer to the first layer (can be null)
376      *  @param bottom_layer = pointer to the last layer (can be null)
377      */
378     void LayerPair( PCB_LAYER_ID* top_layer, PCB_LAYER_ID* bottom_layer ) const;
379 
380     PCB_LAYER_ID TopLayer() const;
381     PCB_LAYER_ID BottomLayer() const;
382 
383     /**
384      * Function SanitizeLayers
385      * Check so that the layers are correct dependin on the type of via, and
386      * so that the top actually is on top.
387      */
388     void SanitizeLayers();
389 
GetPosition()390     wxPoint GetPosition() const override {  return m_Start; }
SetPosition(const wxPoint & aPoint)391     void SetPosition( const wxPoint& aPoint ) override { m_Start = aPoint;  m_End = aPoint; }
392 
393     void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
394 
395     bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override;
396     bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override;
397 
GetClass()398     wxString GetClass() const override
399     {
400         return wxT( "PCB_VIA" );
401     }
402 
403     wxString GetSelectMenuText( EDA_UNITS aUnits ) const override;
404 
405     BITMAPS GetMenuImage() const override;
406 
407     EDA_ITEM* Clone() const override;
408 
409     void ViewGetLayers( int aLayers[], int& aCount ) const override;
410 
411     double ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override;
412 
413     void Flip( const wxPoint& aCentre, bool aFlipLeftRight ) override;
414 
415 #if defined (DEBUG)
Show(int nestLevel,std::ostream & os)416     void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
417 #endif
418 
419     int GetMinAnnulus( PCB_LAYER_ID aLayer, wxString* aSource ) const;
420 
421     /**
422      * Sets the unconnected removal property.  If true, the copper is removed on zone fill
423      * or when specifically requested when the via is not connected on a layer.
424      */
SetRemoveUnconnected(bool aSet)425     void SetRemoveUnconnected( bool aSet )      { m_removeUnconnectedLayer = aSet; }
GetRemoveUnconnected()426     bool GetRemoveUnconnected() const           { return m_removeUnconnectedLayer; }
427 
428     /**
429      * Sets whether we keep the top and bottom connections even if they are not connected
430      */
SetKeepTopBottom(bool aSet)431     void SetKeepTopBottom( bool aSet )      { m_keepTopBottomLayer = aSet; }
GetKeepTopBottom()432     bool GetKeepTopBottom() const           { return m_keepTopBottomLayer; }
433 
434     /**
435      * Checks to see whether the via should have a pad on the specific layer
436      * @param aLayer Layer to check for connectivity
437      * @return true if connected by pad or track (or optionally zone)
438      */
439     bool FlashLayer( int aLayer ) const;
440 
441     /**
442      * Checks to see if the via is present on any of the layers in the set
443      * @param aLayers set of layers to check the via against
444      * @return true if connected by pad or track (or optionally zone) on any of the associated layers
445      */
446     bool FlashLayer( LSET aLayers ) const;
447 
448     /**
449      * Function SetDrill
450      * sets the drill value for vias.
451      * @param aDrill is the new drill diameter
452     */
SetDrill(int aDrill)453     void SetDrill( int aDrill )             { m_drill = aDrill; }
454 
455     /**
456      * Function GetDrill
457      * returns the local drill setting for this PCB_VIA.  If you want the calculated value,
458      * use GetDrillValue() instead.
459      */
GetDrill()460     int GetDrill() const                    { return m_drill; }
461 
462     /**
463      * Function GetDrillValue
464      * "calculates" the drill value for vias (m-Drill if > 0, or default
465      * drill value for the board.
466      * @return real drill_value
467     */
468     int GetDrillValue() const;
469 
470     /**
471      * Function SetDrillDefault
472      * sets the drill value for vias to the default value #UNDEFINED_DRILL_DIAMETER.
473     */
SetDrillDefault()474     void SetDrillDefault()      { m_drill = UNDEFINED_DRILL_DIAMETER; }
475 
476     /**
477      * Checks if the via is a free via (as opposed to one created on a track by the router).
478      * Free vias don't have their nets automatically updated by the connectivity algorithm.
479      * @return true if the via is a free via
480      */
GetIsFree()481     bool GetIsFree() const { return m_isFree; }
482     void SetIsFree( bool aFree = true ) { m_isFree = aFree; }
483 
484     /**
485      * Function IsDrillDefault
486      * @return true if the drill value is default value (-1)
487     */
IsDrillDefault()488     bool IsDrillDefault() const { return m_drill <= 0; }
489 
490     void SwapData( BOARD_ITEM* aImage ) override;
491 
492     // @copydoc BOARD_ITEM::GetEffectiveShape
493     std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const override;
494 
495 protected:
496     wxString layerMaskDescribe() const override;
497 
498 private:
499     /// The bottom layer of the via (the top layer is in m_layer)
500     PCB_LAYER_ID m_bottomLayer;
501 
502     VIATYPE      m_viaType;                  ///< through, blind/buried or micro
503 
504     int          m_drill;                    ///< for vias: via drill (- 1 for default value)
505 
506     bool         m_removeUnconnectedLayer;   ///< Remove unconnected copper on a via
507     bool         m_keepTopBottomLayer;       ///< Keep the top and bottom annular rings
508     bool         m_isFree;                   ///< "Free" vias don't get their nets auto-updated
509 };
510 
511 
512 #endif // CLASS_TRACK_H
513