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