1 /* 2 VeroRoute - Qt based Veroboard/Perfboard/PCB layout & routing application. 3 4 Copyright (C) 2017 Alex Lawrow ( dralx@users.sourceforge.net ) 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (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 <http://www.gnu.org/licenses/>. 18 */ 19 20 #pragma once 21 22 #include "FootPrint.h" 23 #include "RectManager.h" 24 #include "CompDefiner.h" 25 26 // For 2-layer boards, the following says which is the prefered layer for a pin to make connections. 27 // This only affects rendered connections between adjacent pins.. 28 // It does not affect connectivity or routing. 29 // The joint preference of adjacent pins determines which layers will show the connection. 30 static const uchar LAYER_X = 0; // No preference 31 static const uchar LAYER_B = 1; // Prefer bottom layer 32 static const uchar LAYER_T = 2; // Prefer top layer 33 34 static const int MAX_PAD_OFFSET_MIL = 50; 35 36 class CompManager; 37 38 // Class to describe a component. 39 // Wires (i.e. jumpers) and markers also use this class even though they are not true components. 40 41 class Component : public FootPrint 42 { 43 public: Component()44 Component() : FootPrint() { Clear(); } ~Component()45 virtual ~Component() override {} Component(const Component & o)46 Component(const Component& o) : FootPrint() { *this = o; } Clear()47 void Clear() 48 { 49 FootPrint::DeAllocate(); 50 SetType(COMP::INVALID); 51 m_id = 0; 52 m_nameStr = m_valueStr = m_prefixStr = m_typeStr = m_importStr = ""; 53 m_lyr = m_row = m_col = m_iLabelOffsetRow = m_iLabelOffsetCol = 0; 54 m_direction = 'W'; 55 m_bIsPlaced = false; 56 m_iPinFlags = 0; 57 m_iPadWidth = 70; 58 m_iHoleWidth = 40; 59 m_bAllowFlyWire = false; 60 m_nodeIdPins.clear(); 61 m_origIdPins1.clear(); 62 m_origIdPins2.clear(); 63 m_layerPrefs.clear(); 64 m_pinOffsetRow.clear(); 65 m_pinOffsetCol.clear(); 66 m_pinLabels.clear(); 67 m_pinAligns.clear(); 68 m_shapes.clear(); 69 } Component(const CompDefiner & definer)70 Component(const CompDefiner& definer) // This method is for building a custom component 71 { 72 Clear(); 73 74 definer.Build(*this); // Use component definer to make the footprint and shapes 75 } Component(CompManager * pCompMgr,const RectManager & rectMgr,const ElementGrid & grid,const int & nLyr,const int & nRowMin,const int & nRowMax,const int & nColMin,const int & nColMax)76 Component(CompManager* pCompMgr, const RectManager& rectMgr, const ElementGrid& grid, const int& nLyr, const int& nRowMin, const int& nRowMax, const int& nColMin, const int& nColMax) 77 { 78 Clear(); 79 80 BuildTrax(pCompMgr, rectMgr, grid, nLyr, nRowMin, nRowMax, nColMin, nColMax); // Build method for "tracks" component 81 82 SetDefaultStrings(); 83 84 m_lyr = nLyr; 85 m_row = nRowMin; 86 m_col = nColMin; 87 m_bIsPlaced = false; // Trax are always created from the board 88 } Component(const std::string & name,const std::string & value,const COMP & eType,std::vector<int> & nodeIdPins)89 Component(const std::string& name, const std::string& value, const COMP& eType, std::vector<int>& nodeIdPins) 90 { 91 Clear(); 92 93 BuildDefault(eType); // Build method for default component 94 95 SetAllowFlyWire(eType == COMP::PAD_FLYINGWIRE); 96 SetDefaultPinFlags(); 97 SetDefaultStrings(); 98 SetDefaultLabelOffsets(); 99 100 const size_t numPins = nodeIdPins.size(); 101 if ( eType == COMP::DIP || eType == COMP::SIP || eType == COMP::SWITCH_ST_DIP ) // Resize DIP/SIP/SWITCH_DIP as needed 102 { 103 const int reqLength = static_cast<int>( ( eType == COMP::SIP ) ? numPins : numPins / 2 ); 104 while ( GetCols() < reqLength ) Stretch(true); // true ==> grow 105 while ( GetCols() > reqLength ) Stretch(false); // false ==> shrink 106 } 107 if ( eType == COMP::STRIP_100 || eType == COMP::BLOCK_100 || eType == COMP::BLOCK_200 ) 108 { 109 const int reqLength = static_cast<int>( ( eType == COMP::BLOCK_200 ) ? 1 + 2 * numPins : numPins ); 110 while ( GetCols() < reqLength ) Stretch(true); // true ==> grow 111 while ( GetCols() > reqLength ) Stretch(false); // false ==> shrink 112 } 113 if ( eType == COMP::SWITCH_ST || eType == COMP::SWITCH_DT ) // Resize non-DIP switches 114 { 115 const int numPoles = static_cast<int>( ( eType == COMP::SWITCH_ST ) ? numPins / 2 : numPins / 3 ); 116 const int reqLength = ( 2 * numPoles ) - 1; 117 while ( GetCols() < reqLength ) Stretch(true); // true ==> grow 118 while ( GetCols() > reqLength ) Stretch(false); // false ==> shrink 119 } 120 m_nameStr = name; 121 m_valueStr = value; 122 AllocatePins( numPins ); 123 std::copy(nodeIdPins.begin(), nodeIdPins.end(), m_nodeIdPins.begin()); 124 125 SetDefaultShapes(); 126 } 127 Component& operator=(const Component& o) 128 { 129 FootPrint::operator=(o); // Call operator= in base class 130 m_id = o.m_id; 131 m_nameStr = o.m_nameStr; 132 m_valueStr = o.m_valueStr; 133 m_prefixStr = o.m_prefixStr; 134 m_typeStr = o.m_typeStr; 135 m_importStr = o.m_importStr; 136 m_lyr = o.m_lyr; 137 m_row = o.m_row; 138 m_col = o.m_col; 139 m_iLabelOffsetRow = o.m_iLabelOffsetRow; 140 m_iLabelOffsetCol = o.m_iLabelOffsetCol; 141 m_direction = o.m_direction; 142 m_bIsPlaced = o.m_bIsPlaced; 143 m_iPinFlags = o.m_iPinFlags; 144 m_iPadWidth = o.m_iPadWidth; 145 m_iHoleWidth = o.m_iHoleWidth; 146 m_bAllowFlyWire = o.m_bAllowFlyWire; 147 AllocatePins( o.GetNumPins() ); 148 std::copy(o.m_nodeIdPins.begin(), o.m_nodeIdPins.end(), m_nodeIdPins.begin()); 149 std::copy(o.m_origIdPins1.begin(), o.m_origIdPins1.end(), m_origIdPins1.begin()); 150 std::copy(o.m_origIdPins2.begin(), o.m_origIdPins2.end(), m_origIdPins2.begin()); 151 std::copy(o.m_layerPrefs.begin(), o.m_layerPrefs.end(), m_layerPrefs.begin()); 152 std::copy(o.m_pinOffsetRow.begin(), o.m_pinOffsetRow.end(), m_pinOffsetRow.begin()); 153 std::copy(o.m_pinOffsetCol.begin(), o.m_pinOffsetCol.end(), m_pinOffsetCol.begin()); 154 std::copy(o.m_pinLabels.begin(), o.m_pinLabels.end(), m_pinLabels.begin()); 155 std::copy(o.m_pinAligns.begin(), o.m_pinAligns.end(), m_pinAligns.begin()); 156 CopyShapes( o ); 157 return *this; 158 } ClearNodeIds()159 void ClearNodeIds() 160 { 161 for (auto& o : m_nodeIdPins) o = BAD_NODEID; 162 for (auto& o : m_origIdPins1) o = BAD_NODEID; 163 for (auto& o : m_origIdPins2) o = BAD_NODEID; 164 for (auto& o : m_layerPrefs) o = LAYER_X; 165 } IsEqual(const Component & o)166 bool IsEqual(const Component& o) const // Compare persisted info 167 { 168 bool bOK = FootPrint::operator==(o) 169 && m_id == o.m_id 170 && m_nameStr == o.m_nameStr 171 && m_valueStr == o.m_valueStr 172 && m_prefixStr == o.m_prefixStr 173 && m_typeStr == o.m_typeStr 174 && m_importStr == o.m_importStr 175 && m_lyr == o.m_lyr 176 && m_row == o.m_row 177 && m_col == o.m_col 178 && m_iLabelOffsetRow == o.m_iLabelOffsetRow 179 && m_iLabelOffsetCol == o.m_iLabelOffsetCol 180 && m_direction == o.m_direction 181 && m_bIsPlaced == o.m_bIsPlaced 182 && m_iPinFlags == o.m_iPinFlags 183 && m_iPadWidth == o.m_iPadWidth 184 && m_iHoleWidth == o.m_iHoleWidth 185 && m_bAllowFlyWire == o.m_bAllowFlyWire 186 && GetNumPins() == o.GetNumPins() 187 && GetNumShapes() == o.GetNumShapes(); 188 for (size_t i = 0; i < GetNumPins() && bOK; i++) 189 { 190 bOK = m_nodeIdPins[i] == o.m_nodeIdPins[i] 191 && m_origIdPins1[i] == o.m_origIdPins1[i] 192 && m_origIdPins2[i] == o.m_origIdPins2[i] 193 && m_layerPrefs[i] == o.m_layerPrefs[i] 194 && m_pinOffsetRow[i] == o.m_pinOffsetRow[i] 195 && m_pinOffsetCol[i] == o.m_pinOffsetCol[i] 196 && m_pinLabels[i] == o.m_pinLabels[i] 197 && m_pinAligns[i] == o.m_pinAligns[i]; 198 } 199 for (size_t i = 0; i < GetNumShapes() && bOK; i++) 200 { 201 bOK = m_shapes[i] == o.m_shapes[i]; 202 } 203 return bOK; 204 } 205 bool operator<(const Component& o) const { return m_id < o.m_id; } 206 bool operator==(const Component& o) const { return m_id == o.m_id; } SetId(const int & i)207 void SetId(const int& i) { m_id = i; } SetNameStr(const std::string & s)208 void SetNameStr(const std::string& s) { m_nameStr = s; } SetValueStr(const std::string & s)209 void SetValueStr(const std::string& s) { m_valueStr = s; } SetPrefixStr(const std::string & s)210 void SetPrefixStr(const std::string& s) { m_prefixStr = s; } SetTypeStr(const std::string & s)211 void SetTypeStr(const std::string& s) { m_typeStr = s; } SetImportStr(const std::string & s)212 void SetImportStr(const std::string& s) { m_importStr = s; } SetNodeId(const size_t & iPinIndex,const int & i)213 void SetNodeId(const size_t& iPinIndex, const int& i) 214 { 215 if ( iPinIndex < m_nodeIdPins.size() ) m_nodeIdPins[iPinIndex] = i; 216 } SetOrigId(const int & lyr,const size_t & iPinIndex,const int & i)217 void SetOrigId(const int& lyr, const size_t& iPinIndex, const int& i) 218 { 219 assert( lyr == 0 || lyr == 1 ); 220 if ( lyr == 0 ) 221 { 222 if ( iPinIndex < m_origIdPins1.size() ) m_origIdPins1[iPinIndex] = i; 223 } 224 else 225 { 226 if ( iPinIndex < m_origIdPins2.size() ) m_origIdPins2[iPinIndex] = i; 227 } 228 } SetLayerPref(const size_t & iPinIndex,const uchar & iPref)229 void SetLayerPref(const size_t& iPinIndex, const uchar& iPref) 230 { 231 if ( iPinIndex < m_layerPrefs.size() ) m_layerPrefs[iPinIndex] = iPref; 232 } SetPinOffsetRow(const size_t & iPinIndex,const int & i)233 void SetPinOffsetRow(const size_t& iPinIndex, const int& i) 234 { 235 if ( iPinIndex < m_pinOffsetRow.size() ) m_pinOffsetRow[iPinIndex] = std::max(-MAX_PAD_OFFSET_MIL, std::min(MAX_PAD_OFFSET_MIL, i)); 236 } SetPinOffsetCol(const size_t & iPinIndex,const int & i)237 void SetPinOffsetCol(const size_t& iPinIndex, const int& i) 238 { 239 if ( iPinIndex < m_pinOffsetCol.size() ) m_pinOffsetCol[iPinIndex] = std::max(-MAX_PAD_OFFSET_MIL, std::min(MAX_PAD_OFFSET_MIL, i)); 240 } SetPinLabel(const size_t & iPinIndex,const std::string & s)241 void SetPinLabel(const size_t& iPinIndex, const std::string& s) 242 { 243 if ( iPinIndex < m_pinLabels.size() ) m_pinLabels[iPinIndex] = s; 244 } SetPinAlign(const size_t & iPinIndex,const int & i)245 void SetPinAlign(const size_t& iPinIndex, const int& i) 246 { 247 if ( iPinIndex < m_pinAligns.size() ) m_pinAligns[iPinIndex] = i; 248 } SetShape(const size_t & iShapeIndex,const Shape & o)249 void SetShape(const size_t& iShapeIndex, const Shape& o) 250 { 251 if ( iShapeIndex < m_shapes.size() ) m_shapes[iShapeIndex] = o; 252 } CopyPinLabels(const Component & o)253 void CopyPinLabels(const Component& o) 254 { 255 assert( m_pinLabels.size() == o.m_pinLabels.size() ); 256 assert( m_pinAligns.size() == o.m_pinAligns.size() ); 257 std::copy(o.m_pinLabels.begin(), o.m_pinLabels.end(), m_pinLabels.begin()); 258 std::copy(o.m_pinAligns.begin(), o.m_pinAligns.end(), m_pinAligns.begin()); 259 } CopyShapes(const Component & o)260 void CopyShapes(const Component& o) 261 { 262 AllocateShapes( o.GetNumShapes() ); 263 std::copy(o.m_shapes.begin(), o.m_shapes.end(), m_shapes.begin()); 264 } AllocatePins(const size_t numPins)265 void AllocatePins(const size_t numPins) 266 { 267 m_nodeIdPins.clear(); m_nodeIdPins.resize(numPins, BAD_NODEID); 268 m_origIdPins1.clear(); m_origIdPins1.resize(numPins, BAD_NODEID); 269 m_origIdPins2.clear(); m_origIdPins2.resize(numPins, BAD_NODEID); 270 m_layerPrefs.clear(); m_layerPrefs.resize(numPins, LAYER_X); 271 m_pinOffsetRow.clear(); m_pinOffsetRow.resize(numPins, 0); 272 m_pinOffsetCol.clear(); m_pinOffsetCol.resize(numPins, 0); 273 m_pinLabels.clear(); m_pinLabels.resize(numPins, ""); 274 m_pinAligns.clear(); m_pinAligns.resize(numPins, Qt::AlignHCenter); 275 SetDefaultPinLabels(); 276 } AllocateShapes(const size_t numShapes)277 void AllocateShapes(const size_t numShapes) 278 { 279 m_shapes.clear(); m_shapes.resize(numShapes, Shape()); 280 } SetLyr(const int & i)281 void SetLyr(const int& i) { m_lyr = i; } SetRow(const int & i)282 void SetRow(const int& i) { m_row = i; } SetCol(const int & i)283 void SetCol(const int& i) { m_col = i; } 284 // void SetLabelOffsetRow(const int& i) { m_iLabelOffsetRow = i; } 285 // void SetLabelOffsetCol(const int& i) { m_iLabelOffsetCol = i; } SetDirection(const char & d)286 void SetDirection(const char& d) { m_direction = d; } SetIsPlaced(const bool & b)287 void SetIsPlaced(const bool& b) { m_bIsPlaced = b; } SetPinFlags(const uchar & i)288 void SetPinFlags(const uchar& i) { m_iPinFlags = i; } SetPadWidth(const int & i)289 void SetPadWidth(const int& i) { m_iPadWidth = i; } SetHoleWidth(const int & i)290 void SetHoleWidth(const int& i) { m_iHoleWidth = i; } SetAllowFlyWire(const bool & b)291 void SetAllowFlyWire(const bool& b) { m_bAllowFlyWire = b; } AddOne(const Shape & s)292 void AddOne(const Shape& s) { m_shapes.push_back(s); } AddTwo(const Shape & s)293 void AddTwo(const Shape& s) // Adds the shape twice. Once with fill only, and once with line only 294 { 295 Shape tmp(s); 296 tmp.SetDrawFill(true); tmp.SetDrawLine(false); m_shapes.push_back(tmp); 297 tmp.SetDrawFill(false); tmp.SetDrawLine(true); m_shapes.push_back(tmp); 298 } GetIsTemplate()299 bool GetIsTemplate() const { return GetId() == BAD_COMPID; } GetId()300 const int& GetId() const { return m_id; } GetNameStr()301 const std::string& GetNameStr() const { return m_nameStr; } GetValueStr()302 const std::string& GetValueStr() const { return m_valueStr; } GetPrefixStr()303 const std::string& GetPrefixStr() const { return m_prefixStr; } GetTypeStr()304 const std::string& GetTypeStr() const { return m_typeStr; } GetImportStr()305 const std::string& GetImportStr() const { return m_importStr; } GetNumPins()306 size_t GetNumPins() const { return m_nodeIdPins.size(); } GetNumShapes()307 size_t GetNumShapes() const { return m_shapes.size(); } GetNodeId(const size_t & iPinIndex)308 const int& GetNodeId(const size_t& iPinIndex) const 309 { 310 static int badNodeId(BAD_NODEID); 311 return ( iPinIndex < m_nodeIdPins.size() ) ? m_nodeIdPins[iPinIndex] : badNodeId; 312 } GetOrigId(const int & lyr,const size_t & iPinIndex)313 const int& GetOrigId(const int& lyr, const size_t& iPinIndex) const 314 { 315 static int badNodeId(BAD_NODEID); 316 if ( lyr == 0 ) 317 return ( iPinIndex < m_origIdPins1.size() ) ? m_origIdPins1[iPinIndex] : badNodeId; 318 else 319 return ( iPinIndex < m_origIdPins2.size() ) ? m_origIdPins2[iPinIndex] : badNodeId; 320 } GetLayerPref(const size_t & iPinIndex)321 const uchar& GetLayerPref(const size_t& iPinIndex) const 322 { 323 static uchar noPref(LAYER_X); 324 return ( iPinIndex < m_layerPrefs.size() ) ? m_layerPrefs[iPinIndex] : noPref; 325 } GetPinOffsetRow(const size_t & iPinIndex)326 const int& GetPinOffsetRow(const size_t& iPinIndex) const 327 { 328 static int defaultOffset(0); 329 return ( iPinIndex < m_pinOffsetRow.size() ) ? m_pinOffsetRow[iPinIndex] : defaultOffset; 330 } GetPinOffsetCol(const size_t & iPinIndex)331 const int& GetPinOffsetCol(const size_t& iPinIndex) const 332 { 333 static int defaultOffset(0); 334 return ( iPinIndex < m_pinOffsetCol.size() ) ? m_pinOffsetCol[iPinIndex] : defaultOffset; 335 } GetPinLabel(const size_t & iPinIndex)336 const std::string& GetPinLabel(const size_t& iPinIndex) const 337 { 338 static const std::string emptyStr(""); 339 return ( iPinIndex < m_pinLabels.size() ) ? m_pinLabels[iPinIndex] : emptyStr; 340 } GetPinAlign(const size_t & iPinIndex)341 const int& GetPinAlign(const size_t& iPinIndex) const 342 { 343 static int defaultAlign(Qt::AlignHCenter); 344 return ( iPinIndex < m_pinAligns.size() ) ? m_pinAligns[iPinIndex] : defaultAlign; 345 } GetShape(const size_t & iShapeIndex)346 const Shape& GetShape(const size_t& iShapeIndex) const 347 { 348 static Shape defaultShape; 349 return ( iShapeIndex < m_shapes.size() ) ? m_shapes[iShapeIndex] : defaultShape; 350 } GetLyr()351 const int& GetLyr() const { return m_lyr; } GetRow()352 const int& GetRow() const { return m_row; } GetCol()353 const int& GetCol() const { return m_col; } 354 // const int& GetLabelOffsetRow() const { return m_iLabelOffsetRow; } 355 // const int& GetLabelOffsetCol() const { return m_iLabelOffsetCol; } GetDirection()356 const char& GetDirection() const { return m_direction; } GetIsPlaced()357 const bool& GetIsPlaced() const { return m_bIsPlaced; } GetPinFlags()358 const uchar& GetPinFlags() const { return m_iPinFlags; } GetPadWidth()359 const int& GetPadWidth() const { return m_iPadWidth; } GetHoleWidth()360 const int& GetHoleWidth() const { return m_iHoleWidth; } GetAllowFlyWire()361 const bool& GetAllowFlyWire() const { return m_bAllowFlyWire; } GetShapes()362 const std::vector<Shape>& GetShapes() const { return m_shapes; } 363 364 // Helpers for labels 365 void SetDefaultLabelOffsets(); 366 void GetLabelOffsets(int& offsetRow, int& offsetCol) const; // w.r.t. screen, not comp rotation 367 void MoveLabelOffsets(const int& deltaRow, const int& deltaCol); // w.r.t. screen, not comp rotation 368 void HandleLegacyLabelOffsets(); // For old VRT files 369 370 // Helpers for custom pads SetCustomPads(const bool & b)371 void SetCustomPads(const bool& b) { if ( b ) SetPinFlags( m_iPinFlags | PIN_CUSTOM ); 372 else SetPinFlags( m_iPinFlags & ~PIN_CUSTOM ); } GetCustomPads()373 bool GetCustomPads() const { return ( GetPinFlags() & PIN_CUSTOM ) != 0; } 374 375 void GetSafeBounds(double& L, double& R, double& T, double& B, bool bFill = true) const 376 { 377 // First consider footprint bounds (for direction 'W') 378 const double dW( 0.5 * GetCols() ), dH( 0.5 * GetRows() ); 379 L = -dW; R = dW; T = -dH; B = dH; 380 // Then consider the list of shapes (for direction 'W') 381 double l,r,t,b; // Working variables 382 for (const auto& o : m_shapes) 383 { 384 if ( !bFill && o.GetDrawFill() ) continue; // If view is not drawing filled shapes, skip them 385 o.GetSafeBounds(l, r, t, b); 386 L = std::min(L,l); T = std::min(T,t); 387 R = std::max(R,r); B = std::max(B,b); 388 } 389 // Handle other component directions 390 switch ( GetDirection() ) 391 { 392 case 'E': l = -R; t = -B; r = -L; b = -T; break; 393 case 'N': l = -B; t = L; r = -T; b = R; break; 394 case 'S': l = T; t = -R; r = B; b = -L; break; 395 default: return; 396 } 397 L = l; T = t; R = r; B = b; 398 } GetFullTypeStr()399 std::string GetFullTypeStr() const // For SIP/DIP types, append the number of pins 400 { 401 std::string str = GetTypeStr(); 402 if ( GetType() == COMP::DIP || GetType() == COMP::SIP ) 403 { 404 char buffer[32] = {'\0'}; 405 sprintf(buffer, "%d", static_cast<int>(GetNumPins())); 406 str += std::string(buffer); // e.g. "DIP16" 407 } 408 return str; 409 } GetFullImportStr()410 std::string GetFullImportStr() const // For SIP/DIP/SWITCH/STRIP/BLOCK types, append the number of pins 411 { 412 std::string str = GetImportStr(); 413 if ( GetType() == COMP::DIP || GetType() == COMP::SIP || 414 GetType() == COMP::SWITCH_DT || GetType() == COMP::SWITCH_ST || GetType() == COMP::SWITCH_ST_DIP || 415 GetType() == COMP::STRIP_100 || GetType() == COMP::BLOCK_100 || GetType() == COMP::BLOCK_200 ) 416 { 417 char buffer[32] = {'\0'}; 418 sprintf(buffer, "%d", static_cast<int>(GetNumPins())); 419 str += std::string(buffer); // e.g. "DIP16" 420 } 421 return str; 422 } 423 // Helpers (account for component direction) GetCompRows()424 const int& GetCompRows() const { return GetRows( GetDirection() ); } GetCompCols()425 const int& GetCompCols() const { return GetCols( GetDirection() ); } GetLastRow()426 int GetLastRow() const { return GetRow() + GetCompRows() - 1; } GetLastCol()427 int GetLastCol() const { return GetCol() + GetCompCols() - 1; } GetCompPinOffsets(const size_t & iPinIndex,int & Xmil,int & Ymil)428 void GetCompPinOffsets(const size_t& iPinIndex, int& Xmil, int& Ymil) const 429 { 430 switch ( GetDirection() ) 431 { 432 case 'E': Xmil = -GetPinOffsetCol(iPinIndex); Ymil = -GetPinOffsetRow(iPinIndex); return; 433 case 'N': Xmil = -GetPinOffsetRow(iPinIndex); Ymil = GetPinOffsetCol(iPinIndex); return; 434 case 'S': Xmil = GetPinOffsetRow(iPinIndex); Ymil = -GetPinOffsetCol(iPinIndex); return; 435 default: Xmil = GetPinOffsetCol(iPinIndex); Ymil = GetPinOffsetRow(iPinIndex); return; 436 } 437 } SetCompPinOffsets(const size_t & iPinIndex,const int & Xmil,const int & Ymil)438 void SetCompPinOffsets(const size_t& iPinIndex, const int& Xmil, const int& Ymil) 439 { 440 switch ( GetDirection() ) 441 { 442 case 'E': SetPinOffsetCol(iPinIndex, -Xmil); SetPinOffsetRow(iPinIndex, -Ymil); return; 443 case 'N': SetPinOffsetRow(iPinIndex, -Xmil); SetPinOffsetCol(iPinIndex, Ymil); return; 444 case 'S': SetPinOffsetRow(iPinIndex, Xmil); SetPinOffsetCol(iPinIndex, -Ymil); return; 445 default: SetPinOffsetCol(iPinIndex, Xmil); SetPinOffsetRow(iPinIndex, Ymil); return; 446 } 447 } IncCompPinOffsets(const size_t & iPinIndex,const int & dX,const int & dY)448 void IncCompPinOffsets(const size_t& iPinIndex, const int& dX, const int& dY) 449 { 450 int Xmil, Ymil; 451 GetCompPinOffsets(iPinIndex, Xmil, Ymil); 452 SetCompPinOffsets(iPinIndex, Xmil + dX, Ymil + dY); 453 } GetUniformPinOffsets()454 bool GetUniformPinOffsets() const // Check if all pins have the same offsets 455 { 456 const size_t iSize = GetNumPins(); 457 if ( iSize < 2 ) return iSize == 1; 458 bool bAllSame(true); 459 for (size_t i = 1; i < iSize && bAllSame; i++) 460 bAllSame = ( m_pinOffsetRow[i] == m_pinOffsetRow[0] ) && ( m_pinOffsetCol[i] == m_pinOffsetCol[0] ); 461 return bAllSame; 462 } GetCompShapeOffsets(int & Xmil,int & Ymil)463 void GetCompShapeOffsets(int& Xmil, int& Ymil) const 464 { 465 if ( GetUniformPinOffsets() ) 466 { 467 switch ( GetDirection() ) 468 { 469 case 'E': Xmil = -m_pinOffsetCol[0]; Ymil = -m_pinOffsetRow[0]; return; 470 case 'N': Xmil = -m_pinOffsetRow[0]; Ymil = m_pinOffsetCol[0]; return; 471 case 'S': Xmil = m_pinOffsetRow[0]; Ymil = -m_pinOffsetCol[0]; return; 472 default: Xmil = m_pinOffsetCol[0]; Ymil = m_pinOffsetRow[0]; return; 473 } 474 } 475 Xmil = Ymil = 0; // Default to 0 offsets 476 } GetCompElement(const int & compRow,const int & compCol)477 const CompElement* GetCompElement(const int& compRow, const int& compCol) const 478 { 479 return FootPrint::Get(0, compRow, compCol, GetDirection()); 480 } GetHasNodeId(int nodeId)481 bool GetHasNodeId(int nodeId) const 482 { 483 for (const auto& i : m_nodeIdPins) if ( i == nodeId ) return true; 484 return false; 485 } Rotate(const bool & bClockWise)486 void Rotate(const bool& bClockWise) 487 { 488 switch( GetDirection() ) // Component direction: 'W','E','N','S' 489 { 490 case 'W': return SetDirection( bClockWise ? 'N' : 'S' ); 491 case 'E': return SetDirection( bClockWise ? 'S' : 'N' ); 492 case 'N': return SetDirection( bClockWise ? 'E' : 'W' ); 493 case 'S': return SetDirection( bClockWise ? 'W' : 'E' ); 494 } 495 } GetHasAssignedPins()496 bool GetHasAssignedPins() const // Check if any pins have a nodeId or pin label set 497 { 498 for (size_t i = 0; i < GetNumPins(); i++) 499 { 500 if ( m_nodeIdPins[i] != BAD_NODEID ) return true; 501 if ( m_pinLabels[i] != CompTypes::GetDefaultPinLabel(i) ) return true; 502 if ( m_pinAligns[i] != CompTypes::GetDefaultPinAlign(i, GetNumPins(), GetType()) ) return true; 503 } 504 return false; 505 } GetAllowCustomPads()506 bool GetAllowCustomPads() const // true ==> allow custom pad and hole widths 507 { 508 switch( GetType() ) 509 { 510 case COMP::TRACKS: return false; 511 case COMP::WIRE: return false; // Not allowed since 2 wires can share a hole 512 default: return GetNumPins() > 0; 513 } 514 } CanStretch(const bool & bGrow)515 bool CanStretch(const bool& bGrow) const 516 { 517 if ( !FootPrint::CanStretch(bGrow) ) return false; 518 switch( GetType() ) 519 { 520 case COMP::SIP: 521 case COMP::DIP: 522 case COMP::STRIP_100: 523 case COMP::BLOCK_100: 524 case COMP::BLOCK_200: 525 case COMP::SWITCH_ST: 526 case COMP::SWITCH_DT: 527 case COMP::SWITCH_ST_DIP: return !GetHasAssignedPins(); 528 default: return true; 529 } 530 } 531 void Stretch(const bool& bGrow, const bool& bUsePCBshapes = false) 532 { 533 FootPrint::Stretch(bGrow); 534 SetDefaultShapes(bUsePCBshapes); // Rebuild the shapes list 535 536 switch( GetType() ) 537 { 538 case COMP::SIP: return AllocatePins( static_cast<size_t>( GetCols() ) ); 539 case COMP::DIP: return AllocatePins( static_cast<size_t>( 2 * GetCols() ) ); 540 case COMP::STRIP_100: return AllocatePins( static_cast<size_t>( GetCols() ) ); 541 case COMP::BLOCK_100: return AllocatePins( static_cast<size_t>( GetCols() ) ); 542 case COMP::BLOCK_200: return AllocatePins( static_cast<size_t>( ( GetCols() - 1 ) / 2 ) ); 543 case COMP::SWITCH_ST: return AllocatePins( static_cast<size_t>( GetCols() + 1 ) ); 544 case COMP::SWITCH_DT: return AllocatePins( static_cast<size_t>( 3 * ( GetCols() + 1 ) / 2 ) ); 545 case COMP::SWITCH_ST_DIP: return AllocatePins( static_cast<size_t>( 2 * GetCols() ) ); 546 default: return; 547 } 548 } 549 void StretchWidth(const bool& bGrow, const bool& bUsePCBshapes = false) 550 { 551 FootPrint::StretchWidth(bGrow); 552 SetDefaultShapes(bUsePCBshapes); // Rebuild the shapes list 553 } SetDefaultPinLabels()554 void SetDefaultPinLabels() 555 { 556 for (size_t i = 0; i < GetNumPins(); i++) 557 { 558 m_pinLabels[i] = CompTypes::GetDefaultPinLabel(i); 559 m_pinAligns[i] = CompTypes::GetDefaultPinAlign(i, GetNumPins(), GetType()); 560 } 561 } GetFootprintRect()562 Rect GetFootprintRect() const 563 { 564 return Rect(GetRow(), GetLastRow(), GetCol(), GetLastCol()); 565 } GetIsTrueComp()566 bool GetIsTrueComp() const // A true component has pins and "owns" the nodeIds on them 567 { 568 switch( GetType() ) 569 { 570 case COMP::INVALID: 571 case COMP::VERO_NUMBER: 572 case COMP::VERO_LETTER: 573 case COMP::MARK: 574 case COMP::WIRE: 575 case COMP::TRACKS: return false; 576 default: return true; 577 } 578 } SetFillColor(const MyRGB & r)579 void SetFillColor(const MyRGB& r) // Gives all shapes the same fill color 580 { 581 for (auto& o : m_shapes) o.SetFillColor(r); 582 } GetNewColor()583 MyRGB GetNewColor() const // returns an un-used color 584 { 585 for (int iColor = 1; iColor <= 0xFFFFFF; iColor++) // Black is used for outlines so start at 1 586 { 587 bool bOK(true); 588 MyRGB tmp(iColor); 589 for (const auto& o : m_shapes) 590 if ( o.GetFillColor() == tmp ) { bOK = false; break; } 591 if ( bOK ) return tmp; 592 } 593 assert(0); 594 return MyRGB(0x000000); 595 } 596 // Merge interface functions UpdateMergeOffsets(MergeOffsets & o)597 virtual void UpdateMergeOffsets(MergeOffsets& o) override 598 { 599 FootPrint::UpdateMergeOffsets(o); // Call UpdateMergeOffsets in base class 600 601 if ( m_id != BAD_COMPID && m_id != TRAX_COMPID ) o.deltaCompId = std::max(o.deltaCompId, m_id + 1); 602 // o.deltaLyr = std::max(o.deltaLyr, m_lyr + GetCompLyrs() + 1); 603 o.deltaRow = std::max(o.deltaRow, m_row + GetCompRows() + 1); 604 // o.deltaCol = std::max(o.deltaCol, m_col + GetCompCols() + 1); 605 for (size_t i = 0; i < GetNumPins(); i++) 606 { 607 if ( m_nodeIdPins[i] != BAD_NODEID ) o.deltaNodeId = std::max(o.deltaNodeId, m_nodeIdPins[i] + 1); 608 if ( m_origIdPins1[i] != BAD_NODEID ) o.deltaNodeId = std::max(o.deltaNodeId, m_origIdPins1[i] + 1); 609 if ( m_origIdPins2[i] != BAD_NODEID ) o.deltaNodeId = std::max(o.deltaNodeId, m_origIdPins2[i] + 1); 610 } 611 } ApplyMergeOffsets(const MergeOffsets & o)612 virtual void ApplyMergeOffsets(const MergeOffsets& o) override 613 { 614 FootPrint::ApplyMergeOffsets(o); // Call ApplyMergeOffsets in base class 615 616 if ( m_id != BAD_COMPID && m_id != TRAX_COMPID) m_id += o.deltaCompId; 617 m_lyr += o.deltaLyr; 618 m_row += o.deltaRow; 619 m_col += o.deltaCol; 620 for (size_t i = 0; i < GetNumPins(); i++) 621 { 622 if ( m_nodeIdPins[i] != BAD_NODEID ) m_nodeIdPins[i] += o.deltaNodeId; 623 if ( m_origIdPins1[i] != BAD_NODEID ) m_origIdPins1[i] += o.deltaNodeId; 624 if ( m_origIdPins2[i] != BAD_NODEID ) m_origIdPins2[i] += o.deltaNodeId; 625 } 626 } 627 void SetDefaultPinFlags(); 628 void SetDefaultStrings(bool bForce = true) 629 { 630 if ( GetPrefixStr().empty() || bForce ) 631 SetPrefixStr( CompTypes::GetDefaultPrefixStr( GetType() ) ); 632 if ( GetTypeStr().empty() || bForce ) 633 SetTypeStr( CompTypes::GetDefaultTypeStr( GetType() ) ); 634 if ( GetImportStr().empty() || bForce || GetType() != COMP::CUSTOM ) 635 SetImportStr( CompTypes::GetDefaultImportStr( GetType() ) ); 636 } 637 void SetDefaultShapes(const bool& bUsePCBshapes = false); 638 void SetDefaultColor(); 639 // Persist interface functions Load(DataStream & inStream)640 virtual void Load(DataStream& inStream) override 641 { 642 FootPrint::Load(inStream); // Load() base class 643 inStream.Load(m_id); 644 if ( m_id == -2 ) SetType(COMP::TRACKS); // Needed to stop old VRTs from crashing 645 inStream.Load(m_nameStr); 646 inStream.Load(m_valueStr); 647 if ( inStream.GetVersion() >= VRT_VERSION_19 ) 648 inStream.Load(m_prefixStr); // Added in VRT_VERSION_19 649 if ( inStream.GetVersion() >= VRT_VERSION_18 ) 650 { 651 inStream.Load(m_typeStr); // Added in VRT_VERSION_18 652 inStream.Load(m_importStr); // Added in VRT_VERSION_18 653 } 654 m_lyr = 0; 655 if ( inStream.GetVersion() >= VRT_VERSION_34 ) 656 inStream.Load(m_lyr); // Added in VRT_VERSION_34 657 inStream.Load(m_row); 658 inStream.Load(m_col); 659 inStream.Load(m_iLabelOffsetRow); 660 inStream.Load(m_iLabelOffsetCol); 661 if ( inStream.GetVersion() < VRT_VERSION_22 ) // Units changed from 1/4 square to 1/16 square in VRT_VERSION_22 662 { 663 m_iLabelOffsetRow *= 4; 664 m_iLabelOffsetCol *= 4; 665 } 666 inStream.Load(m_direction); 667 inStream.Load(m_bIsPlaced); 668 if ( inStream.GetVersion() >= VRT_VERSION_19 ) 669 inStream.Load(m_iPinFlags); // Added in VRT_VERSION_19 670 m_iPadWidth = 70; 671 m_iHoleWidth = 40; 672 if ( inStream.GetVersion() >= VRT_VERSION_39 ) 673 { 674 inStream.Load(m_iPadWidth); // Added in VRT_VERSION_39 675 inStream.Load(m_iHoleWidth); // Added in VRT_VERSION_39 676 } 677 m_bAllowFlyWire = false; 678 if ( inStream.GetVersion() >= VRT_VERSION_47 ) 679 inStream.Load(m_bAllowFlyWire); // Added in VRT_VERSION_47 680 unsigned int numPins(0); 681 inStream.Load(numPins); 682 AllocatePins(numPins); 683 for (unsigned int i = 0; i < numPins; i++) 684 { 685 inStream.Load(m_nodeIdPins[i]); 686 inStream.Load(m_origIdPins1[i]); 687 if ( inStream.GetVersion() >= VRT_VERSION_34 ) 688 inStream.Load(m_origIdPins2[i]); // Added in VRT_VERSION_34 689 if ( inStream.GetVersion() >= VRT_VERSION_45 ) 690 inStream.Load(m_layerPrefs[i]); // Added in VRT_VERSION_45 691 if ( inStream.GetVersion() >= VRT_VERSION_46 ) 692 { 693 inStream.Load(m_pinOffsetRow[i]); // Added in VRT_VERSION_46 694 inStream.Load(m_pinOffsetCol[i]); // Added in VRT_VERSION_46 695 } 696 if ( inStream.GetVersion() >= VRT_VERSION_7 ) 697 inStream.Load(m_pinLabels[i]); // Added in VRT_VERSION_7 698 if ( inStream.GetVersion() >= VRT_VERSION_30 ) 699 inStream.Load(m_pinAligns[i]); // Added in VRT_VERSION_30 700 } 701 if ( inStream.GetVersion() >= VRT_VERSION_18 ) 702 { 703 unsigned int numShapes(0); 704 inStream.Load(numShapes); // Added in VRT_VERSION_18 705 AllocateShapes(numShapes); 706 for (unsigned int i = 0; i < numShapes; i++) 707 m_shapes[i].Load(inStream); // Added in VRT_VERSION_18 708 } 709 if ( inStream.GetVersion() < VRT_VERSION_31 ) 710 HandleLegacyLabelOffsets(); 711 // Try to fix any missing definitions 712 SetDefaultPinFlags(); 713 SetDefaultStrings(false); // false ==> only set empty (m_prefixStr, m_guiStr, m_importStr) 714 SetDefaultShapes(); 715 } Save(DataStream & outStream)716 virtual void Save(DataStream& outStream) override 717 { 718 FootPrint::Save(outStream); // Save() base class 719 outStream.Save(m_id); 720 outStream.Save(m_nameStr); 721 outStream.Save(m_valueStr); 722 outStream.Save(m_prefixStr); // Added in VRT_VERSION_19 723 outStream.Save(m_typeStr); // Added in VRT_VERSION_18 724 outStream.Save(m_importStr); // Added in VRT_VERSION_18 725 outStream.Save(m_lyr); // Added in VRT_VERSION_34 726 outStream.Save(m_row); 727 outStream.Save(m_col); 728 outStream.Save(m_iLabelOffsetRow); 729 outStream.Save(m_iLabelOffsetCol); 730 outStream.Save(m_direction); 731 outStream.Save(m_bIsPlaced); 732 outStream.Save(m_iPinFlags); // Added in VRT_VERSION_19 733 outStream.Save(m_iPadWidth); // Added in VRT_VERSION_39 734 outStream.Save(m_iHoleWidth); // Added in VRT_VERSION_39 735 outStream.Save(m_bAllowFlyWire); // Added in VRT_VERSION_47 736 const unsigned int numPins = static_cast<unsigned int>( GetNumPins() ); 737 outStream.Save(numPins); 738 for (unsigned int i = 0; i < numPins; i++) 739 { 740 outStream.Save(m_nodeIdPins[i]); 741 outStream.Save(m_origIdPins1[i]); 742 outStream.Save(m_origIdPins2[i]); // Added in VRT_VERSION_34 743 outStream.Save(m_layerPrefs[i]); // Added in VRT_VERSION_45 744 outStream.Save(m_pinOffsetRow[i]); // Added in VRT_VERSION_46 745 outStream.Save(m_pinOffsetCol[i]); // Added in VRT_VERSION_46 746 outStream.Save(m_pinLabels[i]); // Added in VRT_VERSION_7 747 outStream.Save(m_pinAligns[i]); // Added in VRT_VERSION_30 748 } 749 const unsigned int numShapes = static_cast<unsigned int>( GetNumShapes() ); 750 outStream.Save(numShapes); // Added in VRT_VERSION_18 751 for (unsigned int i = 0; i < numShapes; i++) 752 m_shapes[i].Save(outStream); // Added in VRT_VERSION_18 753 } 754 private: 755 int m_id; // Component ID. (BAD_COMPID ==> a component template) 756 std::string m_nameStr; // Name label 757 std::string m_valueStr; // Value label 758 std::string m_prefixStr; // The prefix for new components (overridden for CUSTOM components). 759 std::string m_typeStr; // The footprint type (overridden for CUSTOM components). 760 std::string m_importStr; // Protel/Tango/OrcadPCB2 footprint name. Only for CUSTOM components !!! 761 std::vector<int> m_nodeIdPins; // NodeIds of the pins 762 std::vector<int> m_origIdPins1; // NodeIds under the pins BEFORE placement (1st layer) 763 std::vector<int> m_origIdPins2; // NodeIds under the pins BEFORE placement (2nd Layer) 764 std::vector<uchar> m_layerPrefs; // Prefered layers of the pins 765 std::vector<int> m_pinOffsetRow; // Pin row offset (-50 mil to +50 mil) to allow pad shifts in PCB mode 766 std::vector<int> m_pinOffsetCol; // Pin row offset (-50 mil to +50 mil) to allow pad shifts in PCB mode 767 std::vector<std::string> m_pinLabels; // Pin labels 768 std::vector<int> m_pinAligns; // Pin label alignments (Qt::AlignLeft,Qt::AlignRight,Qt::AlignHCenter) 769 std::vector<Shape> m_shapes; // For rendering components. Coordinates are RELATIVE to footprint centre. 770 uchar m_iPinFlags; // 1 ==> PIN_RECT, 2 ==> PIN_LABELS, 4 ==> PIN_CUSTOM 771 int m_iPadWidth; // Used if the PIN_CUSTOM flag is set 772 int m_iHoleWidth; // Used if the PIN_CUSTOM flag is set 773 bool m_bAllowFlyWire; // For single pin parts only 774 // Current placement in board 775 int m_lyr; // Board layer for component 776 int m_row; // Board row for top-left element of footprint 777 int m_col; // Board col for top-left element of footprint 778 int m_iLabelOffsetRow; // Label offset in units of 1/16 of a grid square 779 int m_iLabelOffsetCol; // Label offset in units of 1/16 of a grid square 780 char m_direction; // Component orienation: 'W', 'E', 'N', 'S' 781 bool m_bIsPlaced; // true ==> placed on board, false ==> floating 782 }; 783