1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
|
/*
VeroRoute - Qt based Veroboard/Perfboard/PCB layout & routing application.
Copyright (C) 2017 Alex Lawrow ( dralx@users.sourceforge.net )
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "Pin.h"
#include "TrackElement.h"
// The board is basically a Grid of "Element" objects.
// "Element" derives from "Pin" and therefore has a description
// of the surface at a location, and the pin index there (if any).
// Each Element in the grid is "glued" to (i.e. has pointers to) it's neighbours.
// There are always 8 "same-layer" neighbours.
// For 2-layer boards, there is an additional "other layer" neighbour.
// Wires (jumpers) "glue" remote elements together within layer 0 (i.e. the base layer).
// This makes all the routing/connectivity code tidy because
// each Element knows what it can be connected to without having
// to go through the parent Grid object.
Q_DECL_CONSTEXPR static const int TRAX_COMPID = -2; // The component manager member m_trax has this ID
Q_DECL_CONSTEXPR static const int BAD_COMPID = -1; // Invalid component ID
Q_DECL_CONSTEXPR static const unsigned int BAD_ROUTEID = UINT_MAX; // Invalid route (i.e. track section) ID
Q_DECL_CONSTEXPR static const unsigned int BAD_MH = UINT_MAX; // "Infinite" MH distance
class Element;
// Quicker to use struct than a std::pair
struct ElementInt
{
ElementInt(const Element* p, unsigned int i) : first(p), second(i) {}
const Element* first;
unsigned int second;
};
// Quicker to use a list than an unordered_map since list is typically small
typedef std::list<ElementInt> WIRELIST; // Helper for chains of wires
class Element : public Pin, public TrackElement
{
public:
// Debug methods that avoid tunneling through layers
size_t GetPinIndexRaw() const { return Pin::GetPinIndex(); }
size_t GetPinIndex2Raw() const { return ( m_pinChar2 == BAD_PINCHAR ) ? BAD_PININDEX : m_pinChar2; }
int GetCompIdRaw() const { return m_compId; }
int GetCompId2Raw() const { return m_compId2; }
uchar GetSurfaceRaw() const { return Pin::GetSurface(); }
uchar GetHoleUseRaw() const { return Pin::GetHoleUse(); }
uchar GetSoicCharRaw() const { return Pin::GetSoicChar(); }
int GetNodeIdRaw() const { return TrackElement::GetNodeId(); }
void SetSurface(uchar c) { return GetBase()->Pin::SetSurface(c); }
void SetHoleUse(uchar c) { return GetBase()->Pin::SetHoleUse(c); }
void SetSoicChar(uchar c) { return GetBase()->Pin::SetSoicChar(c); }
void SetOccupancyTH(bool bWire) { return GetBase()->Pin::SetOccupancyTH(bWire); }
const uchar& GetSurface() const { return GetBaseConst()->Pin::GetSurface(); }
const uchar& GetHoleUse() const { return GetBaseConst()->Pin::GetHoleUse(); }
bool GetIsHole() const { return GetBaseConst()->Pin::GetIsHole(); }
uchar GetSoicChar() const { return GetBaseConst()->Pin::GetSoicChar(); }
bool GetIsBotLyr() const { const Element* const p = GetNbr(NBR_X); return p == nullptr || p > this; }
bool GetIsTopLyr() const { const Element* const p = GetNbr(NBR_X); return p != nullptr && p < this; }
bool GetSoicProtected() const { return GetSoicChar() & ( GetIsTopLyr() ? SOIC_TRACKS_TOP : SOIC_TRACKS_BOT ); }
const int& GetNodeId() const
{
auto pBase = GetBaseConst(); return ( pBase != this && GetHasPinTH() ) ? pBase->TrackElement::GetNodeId() : TrackElement::GetNodeId();
}
void SetNodeId(int i) // Only called via the parent board method Board::SetNodeId()
{
TrackElement::SetNodeId(i);
// Update usage flags for connections emanating from "this" element.
for (int iNbr = 0; iNbr < NUM_NBRS; iNbr++)
if ( GetNbr(iNbr) ) UpdateUsed(iNbr);
// Update usage flags for diagonals that cut across the LT,RT,LB,RB diagonals.
// Call these LTX,RTX,LBX,RBX respectively.
// The point of doing this is that if "this" element has a diagonal connection that
// we've just cleared, then previously blocked diagonals may now be usable.
GetNbr(NBR_L)->UpdateUsed(NBR_RT); GetNbr(NBR_R)->UpdateUsed(NBR_LT); // LTX, RTX
GetNbr(NBR_L)->UpdateUsed(NBR_RB); GetNbr(NBR_R)->UpdateUsed(NBR_LB); // LBX, RBX
auto pBase = GetBase(); if ( pBase != this && GetHasPinTH() ) pBase->SetNodeId(i);
}
Element() : Pin(), TrackElement() { ZeroConnectionPointers(); }
Element(const Element& o) : Pin(o), TrackElement(o) { *this = o; } // This is never used
virtual ~Element() override {}
void ZeroConnectionPointers()
{
memset(m_pNbr, 0, NUM_NBRS * sizeof(Element*));
memset(m_pW, 0, 2 * sizeof(Element*));
}
Element& operator=(const Element& o)
{
Pin::operator=(o); // Call operator= in base class
TrackElement::operator=(o); // Call operator= in base class
m_bIsMark = o.m_bIsMark;
m_compId = o.m_compId;
m_compId2 = o.m_compId2;
m_pinChar2 = o.m_pinChar2;
m_bSolderR = o.m_bSolderR;
m_bIsVia = o.m_bIsVia;
// m_iRoutable = o.m_iRoutable; // This should only be set by the Board::Glue() method
m_MH = o.m_MH;
m_maxMH = o.m_maxMH;
m_routeId = o.m_routeId;
// Zero the connection pointers m_pNbr[] and m_pW[].
// These should only be set by Board::GlueNbrs() and Board::GlueWires().
// m_pW can also be modified by the methods Board::PutDown() and Board::TakeOff().
ZeroConnectionPointers();
return *this;
}
bool operator==(const Element& o) const // Compare persisted info only
{
return Pin::operator==(o)
&& TrackElement::operator==(o)
&& m_bIsMark == o.m_bIsMark
&& m_compId == o.m_compId
&& m_compId2 == o.m_compId2
&& m_pinChar2 == o.m_pinChar2;
}
bool operator!=(const Element& o) const
{
return !(*this == o);
}
void SetIsMark(bool b) { GetBase()->m_bIsMark = b; }
void SetSolderR(bool b) { GetBase()->m_bSolderR = b; }
void SetIsVia(bool b) { GetBase()->m_bIsVia = b; }
void SetRoutable(int i) { m_iRoutable = i; }
void SetRouteId(unsigned int i) { m_routeId = i; }
void ResetMH()
{
m_routeId = BAD_ROUTEID; // Wipe RouteId
m_MH = BAD_MH; // Set "infinite" MH distance.
m_maxMH = 0; // Zero max MH parameter
}
void UpdateMH(unsigned int iRouteID, unsigned int iMH, unsigned int& iMaxMH)
{
assert( m_MH == BAD_MH ); // Should only ever write the MH once
iMaxMH = std::max(iMaxMH, iMH); // Update iMaxMH for output before storing it
m_routeId = iRouteID;
m_MH = iMH;
m_maxMH = iMaxMH;
}
void SetNbr(int iNbr, Element* p) { m_pNbr[iNbr] = p; }
void ClearWires() { SetW(0, nullptr); SetW(1, nullptr); }
bool GetHasWire() const { return GetW(0) != nullptr || GetW(1) != nullptr; }
int GetNumWires() const
{
int nCount(0);
for (int iSlot = 0; iSlot < 2; iSlot++) if ( GetW(iSlot) != nullptr ) nCount++;
return nCount;
}
int GetNumUsedSlots() const
{
int nCount(0);
for (int iSlot = 0; iSlot < 2; iSlot++) if ( GetSlotCompId(iSlot) != BAD_COMPID ) nCount++;
return nCount;
}
int GetFirstUsedSlot() const
{
for (int iSlot = 0; iSlot < 2; iSlot++) if ( GetSlotCompId(iSlot) != BAD_COMPID ) return iSlot;
assert(0);
return -1;
}
int GetFreeSlot() const
{
for (int iSlot = 0; iSlot < 2; iSlot++) if ( GetSlotCompId(iSlot) == BAD_COMPID ) return iSlot;
assert(0);
return -1;
}
int GetSlotFromCompId(int compId) const
{
assert( GetCompId() != GetCompId2() || GetCompId() == BAD_COMPID );
for (int iSlot = 0; iSlot < 2; iSlot++) if ( GetSlotCompId(iSlot) == compId ) return iSlot;
return -1;
}
void SetSlotInfo(int iSlot, size_t pinIndex, int compId)
{
SetSlotPinIndex(iSlot, pinIndex);
SetSlotCompId(iSlot, compId);
}
void SetSlotPinIndex(int iSlot, size_t pinIndex)
{
switch( iSlot )
{
case 0: return SetPinIndex(pinIndex);
case 1: return SetPinIndex2(pinIndex);
default: assert(0);
}
}
void SetSlotCompId(int iSlot, int compId)
{
switch( iSlot )
{
case 0: return SetCompId(compId);
case 1: return SetCompId2(compId);
default: assert(0);
}
}
void GetSlotInfo(int iSlot, size_t& pinIndex, int& compId) const
{
switch( iSlot )
{
case 0: pinIndex = GetPinIndex(); compId = GetCompId(); return;
case 1: pinIndex = GetPinIndex2(); compId = GetCompId2(); return;
default: pinIndex = BAD_PININDEX; compId = BAD_COMPID; assert(0);
}
}
size_t GetSlotPinIndex(int iSlot) const
{
switch( iSlot )
{
case 0: return GetPinIndex();
case 1: return GetPinIndex2();
default: assert(0); return BAD_PININDEX;
}
}
int GetSlotCompId(int iSlot) const
{
switch( iSlot )
{
case 0: return GetCompId();
case 1: return GetCompId2();
default: assert(0); return BAD_COMPID;
}
}
bool GetWireExists(const Element* p) const
{
return p != nullptr && ( GetW(0) == p || GetW(1) == p );
}
bool GetCompExists(int compId) const
{
return compId != BAD_COMPID && ( GetCompId() == compId || GetCompId2() == compId );
}
void SetW(int iSlot, Element* p)
{
assert( !GetWireExists(p) ); // No duplicates allowed
assert( iSlot == 0 || iSlot == 1 );
GetBase()->m_pW[iSlot] = p;
}
void SetMH(unsigned int iMH) { m_MH = iMH; }
const bool& GetIsMark() const { return GetBaseConst()->m_bIsMark; }
int GetNumCompIds() const { int i(0); if ( GetCompId() != BAD_COMPID ) i++; if ( GetCompId2() != BAD_COMPID ) i++; return i; }
bool GetHasComp() const { return GetCompId() != BAD_COMPID || GetCompId2() != BAD_COMPID; }
bool GetHasPinLegacy() const { return GetIsPin() || GetIsPin2(); } // Only kept for legacy purposes (e.g. old VRTs don't have SOIC codes)
bool GetHasPin() const { return GetSoicChar() & (SOIC_PAD|SOIC_THL); } // true ==> Have TH pin/SOIC pad on either layer
bool GetHasPinTH() const { return GetSoicChar() & SOIC_THL; } // true ==> Have TH pin on either layer
bool GetHasPinSOIC() const { return GetSoicChar() & SOIC_PAD; } // true ==> Have SOIC pad on either layer
bool GetLyrHasPin() const { return GetHasPinTH() || ( GetHasPinSOIC() && GetIsTopLyr() ); }
const bool& GetSolderR() const { return GetBaseConst()->m_bSolderR; }
const bool& GetIsVia() const { return GetBaseConst()->m_bIsVia; }
const int& GetRoutable() const { return m_iRoutable; }
const unsigned int& GetRouteId() const { return m_routeId; }
const unsigned int& GetMH() const { return m_MH; }
const unsigned int& GetMaxMH() const { return m_maxMH; }
Element* GetNbr(int iNbr) const { return m_pNbr[iNbr]; }
Element* GetW(int iSlot) const { return GetBaseConst()->m_pW[iSlot]; }
bool GetPinSupportsOffsetPads() const { return GetHasPinTH() && !GetHasWire(); }
bool GetPinSupportsLayerPref() const { return GetHasPinTH() && !GetHasWire(); }
// Helpers
bool HaveNoBlankPins(int iNbr) const
{
const Element* pLyr = this;
const Element* pNbr = pLyr->GetNbr(iNbr);
return ( !pLyr->GetLyrHasPin() || pLyr->GetNodeId() != BAD_NODEID || pLyr->GetHasWire() ) && // Only allow routing FROM blank pins if they are on wires
( !pNbr->GetLyrHasPin() || pNbr->GetNodeId() != BAD_NODEID || pNbr->GetHasWire() ); // Only allow routing TO blank pins if they are on wires
}
void GetWireList(WIRELIST& wireList) const
{
wireList.clear();
return UpdateWireList(wireList, 0);
}
// Connectivity helpers
void UpdateUsed(int iNbr)
{
const bool bUsed = GetNodeId() != BAD_NODEID
&& GetNodeId() == GetNbr(iNbr)->GetNodeId()
&& !IsBlocked(iNbr, GetNodeId());
SetUsed(iNbr, bUsed);
m_pNbr[iNbr]->SetUsed(Opposite(iNbr), bUsed); // Keep consistent with nbr
}
void ToggleUsed(int iNbr)
{
ToggleCodeBit(iNbr, m_iCode);
ToggleCodeBit(Opposite(iNbr), m_pNbr[iNbr]->m_iCode); // Keep consistent with nbr
// Toggles are only done by the user so set the flag accordingly
Element* pNbr = GetNbr(iNbr);
WipeFlagBits(AUTOSET|VEROSET); MarkFlagBits(USERSET);
pNbr->WipeFlagBits(AUTOSET|VEROSET); pNbr->MarkFlagBits(USERSET);
// Handle wire ends
Element* pW = GetW(0); if ( pW ) { pW->WipeFlagBits(AUTOSET|VEROSET); pW->MarkFlagBits(USERSET); }
pW = GetW(1); if ( pW ) { pW->WipeFlagBits(AUTOSET|VEROSET); pW->MarkFlagBits(USERSET); }
pW = pNbr->GetW(0); if ( pW ) { pW->WipeFlagBits(AUTOSET|VEROSET); pW->MarkFlagBits(USERSET); }
pW = pNbr->GetW(1); if ( pW ) { pW->WipeFlagBits(AUTOSET|VEROSET); pW->MarkFlagBits(USERSET); }
}
bool CanSwapDiagLinks()
{
// Take "this" to be the bottom right element in group of 4 squares
// "LT" is the diagonal from "this" to m_pLT
// "LTX" is the diagonal that cuts across it (from m_pL to m_pT)
return GetNodeId() == GetNbr(NBR_LT)->GetNodeId() && // LT: "this" and LT must have same nodeId
GetNbr(NBR_L)->GetNodeId() == GetNbr(NBR_T)->GetNodeId() && // LTX: L and T must have same nodeId
GetNbr(NBR_L)->IsClash( GetNodeId() ); // L and "this" must have clashing nodeIds
}
bool SwapDiagLinks()
{
if ( !CanSwapDiagLinks() ) return false;
// Swap (by inverting flags) if we have competing diagonals
ToggleUsed(NBR_LT);
GetNbr(NBR_L)->ToggleUsed(NBR_RT);
return true;
}
bool IsDiagNbr(const Element* p) const
{
assert( p != nullptr ); // Sanity check
for (int iNbr = 1; iNbr < 8; iNbr += 2)
if ( GetNbr(iNbr) == p ) return true;
return false;
}
bool IsNbr(const Element* p) const
{
assert( p != nullptr ); // Sanity check
for (int iNbr = 0; iNbr < NUM_NBRS; iNbr++)
if ( GetNbr(iNbr) == p ) return true;
return false;
}
bool IsUselessWire(int iNbr, int nodeId) const // Helper: true ==> painting nbr with nodeId is wasteful
{
const Element* pWA = GetNbr(iNbr);
if ( pWA->GetHasWire() )
{
const Element* pWB0 = pWA->GetW(0);
const Element* pWB1 = pWA->GetW(1);
// pWA and pWB are opposite ends of a wire.
// If these ends both neighbour a common element with the specified nodeId,
// then it is wasteful to paint the wire with that nodeId too, since the
// common element already provides a connection.
for (int iNbr = 0; iNbr < NUM_NBRS; iNbr++)
{
const Element* p = pWA->GetNbr(iNbr);
if ( p == nullptr || p->GetNodeId() != nodeId ) continue;
if ( pWB0 != nullptr && pWB0->IsNbr(p) ) return true;
if ( pWB1 != nullptr && pWB1->IsNbr(p) ) return true;
}
}
return false;
}
bool IsBlocked(int iNbr, int nodeId) const // Helper: true ==> assiging nodeId to "this" blocks the iNbr direction
{
assert(nodeId != BAD_NODEID);
if ( !ReadCodeBit(iNbr, GetRoutable() ) ) return true; // Block toroidal connections at board edges
auto pNbr = GetNbr(iNbr);
if ( pNbr->IsClash(nodeId) ) return true; // Check if nbr has a clashing nodeId assigned to it
if ( pNbr->GetIsHole() ) return true; // Block connections to holes
if ( pNbr->GetSoicProtected() ) return true; // Block connections to SOIC area
switch( iNbr ) // Block diagonals crossing the SOIC area
{
case NBR_LT: if ( GetNbr(NBR_L)->GetSoicProtected() || GetNbr(NBR_T)->GetSoicProtected() ) return true; break;
case NBR_RT: if ( GetNbr(NBR_R)->GetSoicProtected() || GetNbr(NBR_T)->GetSoicProtected() ) return true; break;
case NBR_LB: if ( GetNbr(NBR_L)->GetSoicProtected() || GetNbr(NBR_B)->GetSoicProtected() ) return true; break;
case NBR_RB: if ( GetNbr(NBR_R)->GetSoicProtected() || GetNbr(NBR_B)->GetSoicProtected() ) return true; break;
}
switch( iNbr ) // Then do additional checks for competing diagonals
{
case NBR_LT: return GetNbr(NBR_L)->IsClash(nodeId) && GetNbr(NBR_L)->GetUsed(NBR_RT);
case NBR_RT: return GetNbr(NBR_R)->IsClash(nodeId) && GetNbr(NBR_R)->GetUsed(NBR_LT);
case NBR_LB: return GetNbr(NBR_L)->IsClash(nodeId) && GetNbr(NBR_L)->GetUsed(NBR_RB);
case NBR_RB: return GetNbr(NBR_R)->IsClash(nodeId) && GetNbr(NBR_R)->GetUsed(NBR_LB);
default: return false;
}
}
// Merge interface functions
virtual void UpdateMergeOffsets(MergeOffsets& o) override
{
Pin::UpdateMergeOffsets(o); // Does nothing
TrackElement::UpdateMergeOffsets(o);
if ( m_compId != BAD_COMPID && m_compId != TRAX_COMPID )
o.deltaCompId = std::max(o.deltaCompId, m_compId + 1);
assert( m_compId2 != TRAX_COMPID );
if ( m_compId2 != BAD_COMPID && m_compId2 != TRAX_COMPID )
o.deltaCompId = std::max(o.deltaCompId, m_compId2 + 1);
}
void FixCorruption()
{
const bool bOK = GetCompId() == BAD_COMPID &&
GetCompId2() == BAD_COMPID &&
GetPinIndex() == BAD_PININDEX &&
GetPinIndex2() == BAD_PININDEX &&
GetSurface() == SURFACE_FREE &&
GetHoleUse() == HOLE_FREE &&
GetSoicChar() == SOIC_FREE &&
GetIsMark() == false;
if ( !bOK )
{
SetCompId(BAD_COMPID);
SetCompId2(BAD_COMPID);
SetPinIndex(BAD_PININDEX);
SetPinIndex2(BAD_PININDEX);
SetSurface(SURFACE_FREE);
SetHoleUse(HOLE_FREE);
SetSoicChar(SOIC_FREE);
SetIsMark(false);
}
}
virtual void ApplyMergeOffsets(const MergeOffsets& o) override
{
Pin::ApplyMergeOffsets(o); // Does nothing
TrackElement::ApplyMergeOffsets(o);
if ( m_compId != BAD_COMPID && m_compId != TRAX_COMPID)
m_compId += o.deltaCompId;
assert( m_compId2 != TRAX_COMPID );
if ( m_compId2 != BAD_COMPID && m_compId2 != TRAX_COMPID)
m_compId2 += o.deltaCompId;
}
void Merge(const Element& o)
{
Pin::Merge(o);
TrackElement::Merge(o);
m_bIsMark = o.m_bIsMark;
m_compId = o.m_compId;
m_compId2 = o.m_compId2;
m_pinChar2 = o.m_pinChar2;
}
// Persist interface functions
virtual void Load(DataStream& inStream) override
{
if ( inStream.GetVersion() < VRT_VERSION_25 )
{
Pin::Load(inStream); // Load() base class
inStream.Load(m_compId);
TrackElement::Load(inStream); // Load() base class
inStream.Load(m_bIsMark);
}
else
{
Pin::Load(inStream); // Load() base class
TrackElement::Load(inStream); // Load() base class
inStream.Load(m_bIsMark);
inStream.Load(m_compId);
}
m_compId2 = BAD_COMPID;
m_pinChar2 = BAD_PINCHAR;
if ( inStream.GetVersion() >= VRT_VERSION_27 )
{
inStream.Load(m_compId2); // Added in VRT_VERSION_27
inStream.Load(m_pinChar2); // Added in VRT_VERSION_27
}
}
virtual void Save(DataStream& outStream) override
{
Pin::Save(outStream); // Save() base class
TrackElement::Save(outStream); // Save() base class
outStream.Save(m_bIsMark);
outStream.Save(m_compId);
outStream.Save(m_compId2); // Added in VRT_VERSION_27
outStream.Save(m_pinChar2); // Added in VRT_VERSION_27
}
private:
Element* GetBase() { Element* p = GetNbr(NBR_X); return p == nullptr || p > this ? this : p; }
const Element* GetBaseConst() const { const Element* p = GetNbr(NBR_X); return p == nullptr || p > this ? this : p; }
const int& GetCompId() const { return GetBaseConst()->m_compId; }
const int& GetCompId2() const { return GetBaseConst()->m_compId2; }
const uchar& GetPinChar2() const { return GetBaseConst()->m_pinChar2; }
bool GetIsPin() const { return GetBaseConst()->Pin::GetIsPin(); }
bool GetIsPin2() const { return GetPinChar2() != BAD_PINCHAR; }
size_t GetPinIndex() const { return GetBaseConst()->Pin::GetPinIndex(); }
size_t GetPinIndex2() const { return ( GetPinChar2() == BAD_PINCHAR ) ? BAD_PININDEX : GetPinChar2(); }
void SetCompId(int i) { GetBase()->m_compId = i; }
void SetCompId2(int i) { GetBase()->m_compId2 = i; }
void SetPinIndex(size_t i) { return GetBase()->Pin::SetPinIndex(i); }
void SetPinIndex2(size_t i) { GetBase()->m_pinChar2 = ( i >= BAD_PINCHAR ) ? BAD_PINCHAR : static_cast<uchar> (i); }
bool WireListHelper(WIRELIST& wireList, const Element* p, unsigned int iStep) const
{
for (auto& o : wireList)
{
if ( o.first != p ) continue;
if ( iStep < o.second ) { o.second = iStep; return true; } else return false;
}
wireList.push_back(ElementInt(p, iStep));
return true;
}
void UpdateWireList(WIRELIST& wireList, unsigned int iStep) const
{
WireListHelper(wireList, this, iStep);
const bool bOK_0 = GetW(0) != nullptr && WireListHelper(wireList, GetW(0), iStep + 1);
const bool bOK_1 = GetW(1) != nullptr && WireListHelper(wireList, GetW(1), iStep + 1);
if ( bOK_0 ) GetW(0)->UpdateWireList(wireList, iStep + 1);
if ( bOK_1 ) GetW(1)->UpdateWireList(wireList, iStep + 1);
}
private:
// Persist info
bool m_bIsMark = false;
int m_compId = BAD_COMPID; // For elements with a valid pinindex, this is the ID of the parent component
int m_compId2 = BAD_COMPID; // Only used when we have 2 wires sharing a hole
uchar m_pinChar2 = BAD_PINCHAR; // Only used when we have 2 wires sharing a hole
// Working variables. Don't persist.
bool m_bSolderR = false; // true ==> have blob of solder to right (for joining vero tracks)
bool m_bIsVia = false; // true ==> have a (candidate) via between layers
int m_iRoutable = 0; // Set by Board::GlueNbrs(). Code bits used to enable/disable connections to neighbours
unsigned int m_routeId = BAD_ROUTEID; // For the routing algorithm.
unsigned int m_MH = BAD_MH; // Manhatten distance to another element. For the routing/connectivity algorithm.
unsigned int m_maxMH = 0; // For the routing algorithm.
// Connection pointers. Set by Board::GlueNbrs() and Board::GlueWires(). Don't persist.
Element* m_pNbr[static_cast<size_t>(NUM_NBRS)]; // 0 to 7 <==> NBR_L to NBR_LB, 8 ==> NBR_X
Element* m_pW[2]; // Up to 2 wires per element. These point to the other end of the wire(s).
};
|