coriolis/katabatic/src/AutoSegment.cpp

1883 lines
59 KiB
C++

// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC/LIP6 2008-2010, All Rights Reserved
//
// ===================================================================
//
// $Id$
//
// x-----------------------------------------------------------------x
// | |
// | C O R I O L I S |
// | K a t a b a t i c - Routing Toolbox |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@asim.lip6.fr |
// | =============================================================== |
// | C++ Module : "./AutoSegment.cpp" |
// | *************************************************************** |
// | U p d a t e s |
// | |
// x-----------------------------------------------------------------x
#include "hurricane/Warning.h"
#include "hurricane/Bug.h"
#include "hurricane/DataBase.h"
#include "hurricane/Technology.h"
#include "hurricane/Horizontal.h"
#include "hurricane/Vertical.h"
#include "crlcore/RoutingGauge.h"
#include "katabatic/Session.h"
#include "katabatic/AutoContact.h"
#include "katabatic/AutoSegment.h"
#include "katabatic/AutoHorizontal.h"
#include "katabatic/AutoVertical.h"
#include "katabatic/GCell.h"
#include "katabatic/KatabaticEngine.h"
namespace {
using namespace std;
using namespace CRL;
using namespace Hurricane;
using namespace Katabatic;
// ---------------------------------------------------------------
// Local Variables.
const char* badAutoSegmentAnchor =
"AutoSegment::create() :\n\n"
" Source and/or target anchor is NOT an <AutoContact> (internal error).\n"
" Source: %s, Target: %s";
const char* dupAutoSegmentAnchor =
"AutoSegment::create() :\n\n"
" Source and Target anchor are the same : %s (internal error).";
const char* badSegment =
"Katabatic::AutoSegment::create () :\n\n"
" Segment between %s and %s\n"
" is neither horizontal nor vertical .\n";
const char* badSegmentSource =
"Katabatic::AutoSegment::create () :\n\n"
" Source anchor of segment %s is not a Contact\n"
" (%s)\n";
const char* badSegmentTarget =
"Katabatic::AutoSegment::create () :\n\n"
" Source anchor of segment %s is not a Contact\n"
" (%s)\n";
const char* mismatchSegmentSource =
"Katabatic::AutoSegment::create () :\n\n"
" Source anchor of segment %s is already an AutoContact\n"
" (%s)\n";
const char* mismatchSegmentTarget =
"Katabatic::AutoSegment::create () :\n\n"
" Target anchor of segment %s is already an AutoContact\n"
" (%s)\n";
// ---------------------------------------------------------------
// Local Functions.
bool getTerminalInterval ( AutoSegment* autoSegment
, AutoContact* fromContact
, bool isHorizontal
, DbU::Unit& min
, DbU::Unit& max
)
{
AutoContact* terminalContact = NULL;
if ( !fromContact ) {
bool found = getTerminalInterval ( autoSegment
, autoSegment->getAutoSource()
, autoSegment->isHorizontal()
, min
, max );
if ( !found )
found = getTerminalInterval ( autoSegment
, autoSegment->getAutoTarget()
, autoSegment->isHorizontal()
, min
, max );
//if ( !found )
// cerr << "[ERROR] Cannot find terminal of " << autoSegment << "." << endl;
return found;
} else {
if ( autoSegment->isGlobal() ) return false;
ltrace(88) << "Examining " << autoSegment << " " << fromContact << endl;
if ( autoSegment->getSource() == autoSegment->getTarget() ) {
cerr << Error("Source & Target are the same :\n"
" %s\n %s"
,getString(autoSegment).c_str()
,getString(autoSegment->getSource()).c_str()) << endl;
}
terminalContact = autoSegment->getAutoSource();
if ( terminalContact == fromContact ) {
terminalContact = autoSegment->getAutoTarget();
}
if ( !terminalContact->isTerminal() ) {
AutoSegment* segment = NULL;
size_t segmentCount = 0;
forEach ( Component*, icomponent, terminalContact->getSlaveComponents() ) {
if ( *icomponent == autoSegment->getSegment() ) continue;
Segment* connex = dynamic_cast<Segment*>(*icomponent);
if ( !connex ) continue;
segment = Session::lookup ( connex );
if ( !segment || !segment->isTerminal() ) continue;
segmentCount++;
}
if ( segmentCount == 1 ) {
return getTerminalInterval ( segment, terminalContact, isHorizontal, min, max );
return false;
}
} else {
ltrace(88) << "Terminal is " << terminalContact << endl;
Box constraintBox = terminalContact->getConstraintBox();
if ( isHorizontal ) {
min = constraintBox.getXMin ();
max = constraintBox.getXMax ();
} else {
min = constraintBox.getYMin ();
max = constraintBox.getYMax ();
}
return true;
}
}
return false;
}
// ---------------------------------------------------------------
// Class : "AttractorsMap".
class AttractorsMap {
// Constructor.
public:
inline AttractorsMap ();
inline size_t getAttractorsCount () const;
DbU::Unit getLowerMedian () const;
DbU::Unit getUpperMedian () const;
void addAttractor ( DbU::Unit position );
protected:
map<DbU::Unit,size_t> _attractors;
size_t _attractorsCount;
};
inline AttractorsMap::AttractorsMap ()
: _attractors(), _attractorsCount(0)
{ }
inline size_t AttractorsMap::getAttractorsCount () const
{
return _attractorsCount;
}
void AttractorsMap::addAttractor ( DbU::Unit position )
{
_attractors[position]++;
_attractorsCount++;
ltrace(88) << "add Attractor @" << DbU::getLambda(position)
<< " [" << _attractors[position] << "]" << endl;
}
DbU::Unit AttractorsMap::getLowerMedian () const
{
size_t median = (_attractorsCount/2) + (_attractorsCount%2);
size_t lower = 0;
map<DbU::Unit,size_t>::const_iterator it = _attractors.begin ();
for ( ; it != _attractors.end() ; it++ ) {
lower += it->second;
if ( lower >= median ) break;
}
return it->first;
}
DbU::Unit AttractorsMap::getUpperMedian () const
{
size_t median = _attractorsCount / 2;
size_t upper = 0;
map<DbU::Unit,size_t>::const_iterator it = _attractors.begin ();
for ( ; it != _attractors.end() ; it++ ) {
upper += it->second;
if ( upper > median ) break;
}
return it->first;
}
} // End of local namespace.
namespace Katabatic {
// -------------------------------------------------------------------
// Class : "Katabatic::AutoSegment::CompareCanonical".
bool AutoSegment::CompareCanonical::operator() ( const AutoSegment* lhs, const AutoSegment* rhs ) const
{
if ( lhs->isCanonical () xor rhs->isCanonical () ) return lhs->isCanonical();
if ( lhs->isCollapsed () xor rhs->isCollapsed () ) return rhs->isCollapsed();
if ( lhs->isSlackenStrap() xor rhs->isSlackenStrap() ) return lhs->isSlackenStrap();
if ( lhs->getSourceU() < rhs->getSourceU() ) return true;
if ( lhs->getSourceU() > rhs->getSourceU() ) return false;
if ( lhs->getLength() > rhs->getLength() ) return true;
if ( lhs->getLength() < rhs->getLength() ) return false;
if ( lhs->isGlobal () xor rhs->isGlobal () ) return lhs->isGlobal();
if ( lhs->isTerminal () xor rhs->isTerminal () ) return rhs->isTerminal();
if ( lhs->isHorizontal() xor rhs->isHorizontal() ) return lhs->isHorizontal();
if ( lhs->getAxis() < rhs->getAxis() ) return true;
if ( lhs->getAxis() > rhs->getAxis() ) return false;
if ( lhs->isFixed() xor rhs->isFixed() ) return lhs->isFixed();
return lhs->getId() < rhs->getId();
}
// -------------------------------------------------------------------
// Class : "Katabatic::AutoSegment::CompareByDepthLength".
bool AutoSegment::CompareByDepthLength::operator() ( AutoSegment* lhs, AutoSegment* rhs ) const
{
if ( Session::getRoutingGauge()->getLayerDepth(lhs->getLayer())
< Session::getRoutingGauge()->getLayerDepth(rhs->getLayer()) )
return true;
if ( Session::getRoutingGauge()->getLayerDepth(lhs->getLayer())
> Session::getRoutingGauge()->getLayerDepth(rhs->getLayer()) )
return false;
return AutoSegment::CompareCanonical() ( lhs, rhs );
}
// -------------------------------------------------------------------
// Class : "Katabatic::AutoSegment".
size_t AutoSegment::_allocateds = 0;
size_t AutoSegment::_globalsCount = 0;
unsigned long AutoSegment::_maxId = 0;
DbU::Unit AutoSegment::getX () const
{
return getSegment()->getX();
}
DbU::Unit AutoSegment::getY () const
{
return getSegment()->getY();
}
AutoContact* AutoSegment::getOppositeAnchor ( AutoContact* anchor ) const
{
return Session::lookup(static_cast<Contact*>(getOppositeAnchor(anchor->getContact())));
}
Interval& AutoSegment::getOptimal ( Interval& i ) const
{
i.getVMin() = getOptimalMin();
i.getVMax() = getOptimalMax();
return i;
}
bool AutoSegment::checkInvalidated () const
{
if ( isInvalidated() )
cerr << Error("%s is invalidated.",getString(this).c_str()) << endl;
return !isInvalidated();
}
void AutoSegment::invalidate ()
{
if ( Session::doDestroyTool() ) return;
_invalidate ();
forEach ( AutoSegment*, isegment, getCollapseds() )
isegment->_invalidate ();
}
void AutoSegment::_invalidate ()
{
if ( !isInvalidated() ) {
ltrace(110) << "AutoSegment::_invalidate() " << this << endl;
setInvalidated ( true );
Session::invalidate ( this );
}
}
void AutoSegment::revalidate ()
{
ltrace(110) << "AutoSegment::revalidate() " << this << endl;
ltracein(110);
setPositions ();
setInvalidated ( false );
ltraceout(110);
}
DbU::Unit AutoSegment::getSlack () const
{
DbU::Unit constraintMin;
DbU::Unit constraintMax;
getConstraints ( constraintMin, constraintMax );
return constraintMax - constraintMin;
}
DbU::Unit AutoSegment::getCost ( DbU::Unit axis ) const
{
DbU::Unit optimal = getOptimalMin();
if ( axis < optimal )
return optimal - axis;
optimal = getOptimalMax();
if ( axis > optimal )
return axis - optimal;
return 0;
}
AutoSegment* AutoSegment::getCanonical ( DbU::Unit& min, DbU::Unit& max )
{
min = getSourcePosition ();
max = getTargetPosition ();
if ( max < min ) swap ( min, max );
AutoSegment* canonical = this;
size_t canonicals = isCanonical();
size_t aligneds = 1;
DbU::Unit collapsedMin;
DbU::Unit collapsedMax;
forEach ( AutoSegment*, isegment, getCollapseds() ) {
if ( isegment->isCanonical() ) {
canonical = *isegment;
canonicals++;
}
collapsedMin = isegment->getSourcePosition();
collapsedMax = isegment->getTargetPosition();
if ( collapsedMax < collapsedMin ) swap ( collapsedMin, collapsedMax );
if ( collapsedMin < min ) min = collapsedMin;
if ( collapsedMax > max ) max = collapsedMax;
aligneds++;
}
if ( (canonicals > 1) || ( !canonicals && (aligneds > 2) ) ) {
cerr << Bug("AutoSegment::getCanonical(): %p:%s"
"\n Bad canonization: %d canonicals out of %d collapseds."
, base(), _getString().c_str(), canonicals, aligneds ) << endl;
int count = 0;
cerr << " " << count++ << ": " << this << endl;
forEach ( AutoSegment*, isegment, getCollapseds() )
cerr << " " << count++ << ": " << *isegment << endl;
}
return canonical;
}
AutoSegments AutoSegment::getOnSourceContact ( unsigned int direction )
{
return AutoSegments_OnContact
( this, getSource() ).getSubSet ( AutoSegments_InDirection(direction) );
}
AutoSegments AutoSegment::getOnTargetContact ( unsigned int direction )
{
return AutoSegments_OnContact
( this, getTarget() ).getSubSet ( AutoSegments_InDirection(direction) );
}
AutoSegments AutoSegment::getCollapseds ( bool withPerpand )
{
return AutoSegments_Collapsed ( this, withPerpand );
}
AutoSegments AutoSegment::getCollapsedPerpandiculars ()
{
return AutoSegments_CollapsedPerpandicular ( this );
}
bool AutoSegment::isCanonicalStrap () const
{
if ( not isStrap() ) return false;
forEach ( AutoSegment*, isegment, const_cast<AutoSegment*>(this)->getCollapseds() ) {
if ( not isegment->isStrap() ) return false;
}
return true;
}
bool AutoSegment::collapse ()
{
if ( _isGlobal ) {
cerr << Error("Global %s cannot be collapsed.",getString(this).c_str()) << endl;
return false;
}
if ( _isCollapsed ) return true;
_isCollapsed = true;
unsigned int direction = (_isHorizontal) ? Constant::Vertical : Constant::Horizontal;
forEach ( AutoSegment*, isegment, AutoSegments_AnchoredBySource(getAutoSource(),direction) ) {
isegment->setCanonical ( false );
}
forEach ( AutoSegment*, isegment, AutoSegments_AnchoredBySource(getAutoTarget(),direction) ) {
isegment->setCanonical ( false );
}
return true;
}
bool AutoSegment::expand ()
{
if ( _isGlobal ) {
cerr << Warning("Global %s already uncollapsed.",getString(this).c_str()) << endl;
return false;
}
if ( !_isCollapsed ) {
cerr << Warning("Local %s already uncollapsed.",getString(this).c_str()) << endl;
return true;
}
_isCollapsed = false;
canonize ();
unsigned int direction = (_isHorizontal) ? Constant::Vertical : Constant::Horizontal;
forEach ( AutoSegment*, segment, getOnSourceContact(direction) ) {
segment->canonize ();
}
forEach ( AutoSegment*, segment, getOnTargetContact(direction) ) {
segment->canonize ();
}
return true;
}
bool AutoSegment::toConstraintAxis ( set<AutoSegment*>* processeds )
{
if ( processeds && (processeds->find(this) != processeds->end()) ) return false;
DbU::Unit constraintMin;
DbU::Unit constraintMax;
getConstraints ( constraintMin, constraintMax );
// Empty constraint interval: ignore.
if ( constraintMin > constraintMax ) return false;
if ( allowOutsideGCell() ) {
// Ugly: hard-wired value of the track spacing.
constraintMin -= DbU::lambda(5.0) * 8;
constraintMax += DbU::lambda(5.0) * 8;
}
if ( getAxis() < constraintMin ) {
setAxis ( constraintMin, Realignate, processeds );
return true;
}
if ( getAxis() > constraintMax ) {
setAxis ( constraintMax, Realignate, processeds );
return true;
}
return false;
}
bool AutoSegment::toOptimalAxis ( set<AutoSegment*>* processeds )
{
if ( processeds && (processeds->find(this) != processeds->end()) ) return false;
DbU::Unit constraintMin;
DbU::Unit constraintMax;
getConstraints ( constraintMin, constraintMax );
DbU::Unit optimalMin = max ( min(getOptimalMin(),constraintMax), constraintMin );
DbU::Unit optimalMax = min ( max(getOptimalMax(),constraintMin), constraintMax );
if ( getAxis() < optimalMin ) {
#if defined(CHECK_DETERMINISM)
cerr << "Order: toOptimalMin "
<< DbU::getValueString(optimalMin) << " ["
<< DbU::getValueString(optimalMin) << ":"
<< DbU::getValueString(optimalMax) << "] ["
<< DbU::getValueString(constraintMin) << ":"
<< DbU::getValueString(constraintMax) << "] "
<< this << endl;
#endif
setAxis ( optimalMin, Realignate|AxisSet, processeds );
return true;
}
if ( getAxis() > optimalMax ) {
#if defined(CHECK_DETERMINISM)
cerr << "Order: toOptimalMax "
<< DbU::getValueString(optimalMin) << " ["
<< DbU::getValueString(optimalMin) << ":"
<< DbU::getValueString(optimalMax) << "] ["
<< DbU::getValueString(constraintMin) << ":"
<< DbU::getValueString(constraintMax) << "] "
<< this << endl;
#endif
setAxis ( optimalMax, Realignate|AxisSet, processeds );
return true;
}
#if defined(CHECK_DETERMINISM)
cerr << "Order: in optimal position "
<< DbU::getValueString(optimalMin) << " ["
<< DbU::getValueString(optimalMin) << ":"
<< DbU::getValueString(optimalMax) << "] ["
<< DbU::getValueString(constraintMin) << ":"
<< DbU::getValueString(constraintMax) << "] "
<< this << endl;
#endif
return false;
}
void AutoSegment::setAxis ( DbU::Unit axis, unsigned int flags, set<AutoSegment*>* processeds )
{
if ( processeds and (processeds->find(this) != processeds->end()) ) return;
if ( ( axis != getAxis() ) and isFixed() ) {
cerr << Error("AutoSegment::setAxis(): Cannot move a fixed segment.\n"
" (on: %s)",_getString().c_str()) << endl;
}
if ( _isUnsetAxis and (flags & AxisSet) ) {
ltrace(200) << "setAxis() - AxisSet flag raised " << this << endl;
_isUnsetAxis = false;
}
if ( ( axis == getAxis() ) and not (flags & Realignate) ) return;
ltrace(200) << "setAxis() @"
<< ((_isHorizontal)?"Y ":"X ") << DbU::getLambda(getAxis())
<< " to " << DbU::getLambda(axis) << " on " << this << endl;
ltracein(80);
alignate ( axis );
if ( processeds ) processeds->insert ( this );
forEach ( AutoSegment*, isegment, getCollapseds() ) {
isegment->alignate ( getAxis() );
if ( flags & AxisSet ) isegment->_isUnsetAxis = false;
if ( processeds ) processeds->insert ( *isegment );
}
ltraceout(80);
}
void AutoSegment::computeOptimal ( set<AutoSegment*>* processeds )
{
ltrace(89) << "computeOptimal() - " << this << endl;
ltracein(89);
if ( processeds && (processeds->find(this) != processeds->end()) ) { ltraceout(89); return; }
if ( _isCollapsed ) {
_optimalMin = 0;
setOptimalMax ( (_isHorizontal) ? _gcell->getBoundingBox().getYMax()
: _gcell->getBoundingBox().getXMax() );
ltraceout(89);
return;
}
DbU::Unit minGCell = getOrigin();
DbU::Unit maxGCell = getExtremity();
DbU::Unit terminalMin;
DbU::Unit terminalMax;
AttractorsMap attractors;
AutoContact* anchor = getAutoSource();
if ( anchor->isTerminal() ) {
Box constraintBox = anchor->getConstraintBox();
if ( isHorizontal() ) {
terminalMin = constraintBox.getYMin ();
terminalMax = constraintBox.getYMax ();
} else {
terminalMin = constraintBox.getXMin ();
terminalMax = constraintBox.getXMax ();
}
attractors.addAttractor ( terminalMin );
if ( terminalMin != terminalMax )
attractors.addAttractor ( terminalMax );
}
anchor = getAutoTarget();
if ( anchor->isTerminal() ) {
Box constraintBox = anchor->getConstraintBox();
if ( isHorizontal() ) {
terminalMin = constraintBox.getYMin ();
terminalMax = constraintBox.getYMax ();
} else {
terminalMin = constraintBox.getXMin ();
terminalMax = constraintBox.getXMax ();
}
attractors.addAttractor ( terminalMin );
if ( terminalMin != terminalMax )
attractors.addAttractor ( terminalMax );
}
forEach ( AutoSegment*, autoSegment, getCollapsedPerpandiculars() ) {
ltrace(89) << "Perpandicular " << *autoSegment << endl;
ltracein(89);
if ( autoSegment->isLocal() ) {
if ( !autoSegment->isTerminal() ) { ltraceout(89); continue; }
DbU::Unit terminalMin;
DbU::Unit terminalMax;
if ( getTerminalInterval ( *autoSegment
, NULL
, isHorizontal()
, terminalMin
, terminalMax ) ) {
attractors.addAttractor ( terminalMin );
if ( terminalMin != terminalMax )
attractors.addAttractor ( terminalMax );
}
} else {
bool isMin = true;
if ( isHorizontal()
&& ( autoSegment->getAutoSource()->getGCell()->getRow() == _gcell->getRow() ) )
isMin = false;
if ( isVertical()
&& ( autoSegment->getAutoSource()->getGCell()->getColumn() == _gcell->getColumn() ) )
isMin = false;
attractors.addAttractor ( (isMin) ? minGCell : maxGCell );
}
ltraceout(89);
}
DbU::Unit optimalMin;
DbU::Unit optimalMax;
DbU::Unit constraintMin;
DbU::Unit constraintMax;
getConstraints ( constraintMin, constraintMax );
if ( attractors.getAttractorsCount() ) {
ltrace(89) << "Lower Median " << DbU::getLambda(attractors.getLowerMedian()) << endl;
ltrace(89) << "Upper Median " << DbU::getLambda(attractors.getUpperMedian()) << endl;
optimalMin = attractors.getLowerMedian();
optimalMax = attractors.getUpperMedian();
} else {
optimalMin = 0;
optimalMax = (_isHorizontal) ? _gcell->getBoundingBox().getYMax()
: _gcell->getBoundingBox().getXMax();
}
setInBound ( constraintMin, constraintMax, optimalMin );
setInBound ( constraintMin, constraintMax, optimalMax );
if ( processeds ) processeds->insert ( this );
setOptimalMin ( optimalMin );
setOptimalMax ( optimalMax );
forEach ( AutoSegment*, autoSegment, getCollapseds() ) {
if ( processeds ) processeds->insert ( *autoSegment );
autoSegment->setOptimalMin ( optimalMin );
autoSegment->setOptimalMax ( optimalMax );
}
ltraceout(89);
}
AutoSegment* AutoSegment::canonize ()
{
ltrace(159) << "canonize() - " << this << endl;
if ( isCanonical() ) {
ltrace(159) << "* " << this << " canonical" << endl;
return this;
}
AutoSegment* canonical = this;
bool hasCanonical = false;
bool isCanonicalLocal = true;
forEach ( AutoSegment*, isegment, getCollapseds() ) {
if ( isegment->isGlobal() ) isCanonicalLocal = false;
if ( isegment->isCanonical() ) {
ltrace(159) << "* " << *isegment << " canonical" << endl;
//return *isegment;
canonical = *isegment;
hasCanonical = true;
break;
}
if ( !hasCanonical ) {
if ( CompareCanonical()(*isegment,canonical) )
canonical = *isegment;
}
}
canonical->setCanonical ( true );
canonical->setCanonicalLocal ( isCanonicalLocal );
// ltrace: 159
if ( isCanonical() ) cerr << "* " << this << " canonical" << endl;
else cerr << "* " << this << endl;
forEach ( AutoSegment*, isegment, getCollapseds() ) {
if ( isegment->isCanonical() ) cerr << "| " << *isegment << " canonical" << endl;
else cerr << "| " << *isegment << endl;
}
return canonical;
}
AutoSegment::AutoSegment ( Segment* segment
, bool isHorizontal
, int type
, bool terminal
, bool collapsed
)
: _isUnsetAxis (true)
, _invalidated (false)
, _isHorizontal (isHorizontal)
, _isTerminal (terminal)
, _isCollapsed (collapsed)
, _isCanonical (false)
, _isFixed (false)
, _strap (false)
, _layerChange (false)
, _slackened (false)
, _slackenStrap (false)
, _allowOutsideGCell(false)
, _id (_maxId++)
, _optimalMin (0)
, _userConstraints (false)
{
//cerr << "AutoSegment::AutoSegment() - <id:" << _id << ">" << endl;
#if defined(CHECK_DETERMINISM)
cerr << "Order: AutoSegment::AutoSegment() - <id:" << _id << ">" << endl;
#endif
AutoContact* source = Session::lookup(dynamic_cast<Contact*>(segment->getSource()));
AutoContact* target = Session::lookup(dynamic_cast<Contact*>(segment->getTarget()));
_allocateds++;
_gcell = source->getGCell();
setOptimalMax ( (_isHorizontal) ? _gcell->getBoundingBox().getYMax()
: _gcell->getBoundingBox().getXMax() );
switch ( type ) {
case AutoSegment::Global: _isGlobal = true; break;
case AutoSegment::Local : _isGlobal = false; break;
case AutoSegment::Guess :
_isGlobal = ( source->getGCell() != target->getGCell() );
break;
}
_globalsCount += (_isGlobal) ? 1 : 0;
_isCanonicalLocal = not _isGlobal;
_computeTerminal ( segment );
//if ( source->isTerminal() or target->isTerminal() ) _isTerminal = true;
//if ( source->isTerminal()
// and target->isTerminal()
// /*and (segment->getLength() < DbU::lambda(25.0))*/
// and (source->getGCell() == target->getGCell()) ) {
// _strap = true;
//}
source->setInvalidatedTopology ( true );
}
void AutoSegment::_preCreate ( Component* source, Component* target )
{
AutoContact* acSource = Session::lookup(dynamic_cast<Contact*>(source));
AutoContact* acTarget = Session::lookup(dynamic_cast<Contact*>(target));
_preCreate ( acSource, acTarget );
}
void AutoSegment::_preCreate ( AutoContact* source, AutoContact* target )
{
if ( !source || !target )
throw Error ( badAutoSegmentAnchor
, ((source)?getString(source).c_str():"NULL")
, ((target)?getString(target).c_str():"NULL")
);
if ( source == target )
throw Error ( dupAutoSegmentAnchor, getString(source).c_str() );
}
void AutoSegment::_postCreate ()
{
Session::invalidate ( getNet() );
Session::link ( this );
invalidate ();
}
void AutoSegment::_preDestroy ()
{
ltrace(200) << "AutoSegment::_preDestroy() - " << (void*)this << endl;
ltracein(90);
Session::unlink ( this );
ltraceout(90);
}
AutoSegment::~AutoSegment ()
{
_allocateds--;
if ( _isGlobal and (_globalsCount > 0) ) _globalsCount--;
}
void AutoSegment::_computeTerminal ( Segment* segment )
{
AutoContact* source = Session::lookup(dynamic_cast<Contact*>(segment->getSource()));
AutoContact* target = Session::lookup(dynamic_cast<Contact*>(segment->getTarget()));
if ( source->isTerminal() or target->isTerminal() ) _isTerminal = true;
}
size_t AutoSegment::getAlignedContacts ( map<AutoContact*,int>& innerContacts )
{
map<AutoContact*,int>::iterator icontact;
innerContacts.clear ();
innerContacts.insert ( make_pair(getAutoSource(),0x1) );
innerContacts.insert ( make_pair(getAutoTarget(),0x4) );
forEach ( AutoSegment*, isegment, getCollapseds() ) {
if ( (icontact = innerContacts.find(isegment->getAutoSource())) != innerContacts.end() ) {
if ( icontact->second & 0x1 ) icontact->second |= 0x2;
else icontact->second |= 0x1;
} else
innerContacts.insert ( make_pair(getAutoSource(),0x1) );
if ( (icontact = innerContacts.find(isegment->getAutoTarget())) != innerContacts.end() ) {
if ( icontact->second & 0x4 ) icontact->second |= 0x8;
else icontact->second |= 0x4;
} else
innerContacts.insert ( make_pair(getAutoTarget(),0x4) );
}
return innerContacts.size();
}
size_t AutoSegment::getPerpandicularsBound ( set<AutoSegment*>& bounds )
{
map<AutoContact*,int> contacts;
map<AutoContact*,int>::iterator icontact;
getAlignedContacts ( contacts );
for ( icontact=contacts.begin() ; icontact != contacts.end() ; icontact++ ) {
if ( (icontact->second == 0x1) or (icontact->second == 0x4) ) {
forEach ( Segment*, isegment, icontact->first->getSlaveComponents().getSubSet<Segment*>() ) {
AutoSegment* autoSegment = Session::lookup ( *isegment );
if ( !autoSegment ) continue;
if ( autoSegment->getDirection() == getDirection() ) continue;
bounds.insert ( autoSegment );
}
}
}
return bounds.size();
}
Interval AutoSegment::getMinSpanU ()
{
map<AutoContact*,int> contacts;
map<AutoContact*,int>::iterator icontact;
getAlignedContacts ( contacts );
DbU::Unit spanMin = DbU::Min;
DbU::Unit spanMax = DbU::Max;
Interval constraints;
unsigned int direction = Constant::perpandicular(getDirection());
for ( icontact=contacts.begin() ; icontact != contacts.end() ; icontact++ ) {
constraints = icontact->first->getUConstraints ( direction );
if ( icontact->second == 0x1 ) {
spanMin = max ( spanMin, constraints.getVMax() );
}
if ( icontact->second == 0x4 ) {
spanMax = min ( spanMax, constraints.getVMin() );
}
}
return Interval(spanMin,spanMax);
}
void AutoSegment::setAllowOutsideGCell ( bool state, bool propagate )
{
if ( allowOutsideGCell() ) return;
_setAllowOutsideGCell ( state );
if ( propagate ) {
forEach ( AutoSegment*, isegment, getCollapseds() ) {
isegment->_setAllowOutsideGCell ( state );
}
}
}
void AutoSegment::_setAllowOutsideGCell ( bool state )
{
ltrace(200) << "_setAllowOutsideGCell() - " << this << endl;
_allowOutsideGCell = state;
}
bool AutoSegment::canGoOutsideGCell () const
{
ltracein(200);
bool goOutsideGCell = getAutoSource()->canGoOutsideGCell(this);
goOutsideGCell = goOutsideGCell and getAutoTarget()->canGoOutsideGCell(this);
if ( !goOutsideGCell ) {
ltraceout(200);
return false;
}
GCell* sourceGCell = getAutoSource()->getGCell();
GCell* leftGCell = NULL;
GCell* rightGCell = NULL;
Interval uside;
bool goLeft = false;
bool goRight = false;
if ( isHorizontal() ) {
uside = sourceGCell->getUSide ( Constant::Vertical );
leftGCell = sourceGCell->getDown();
rightGCell = sourceGCell->getUp ();
} else {
uside = sourceGCell->getUSide ( Constant::Horizontal );
leftGCell = sourceGCell->getLeft ();
rightGCell = sourceGCell->getRight();
}
DbU::Unit constraintMin;
DbU::Unit constraintMax;
getConstraints ( constraintMin, constraintMax );
if ( leftGCell && (uside.getVMin() >= constraintMin) ) {
ltrace(200) << "Can go Left." << endl;
goLeft = true;
}
// Ugly: Must use the right compensator for VMax.
if ( rightGCell && (uside.getVMax() <= constraintMax)+DbU::lambda(1.0) ) {
ltrace(200) << "Can go Right." << endl;
goRight = true;
}
goOutsideGCell = goOutsideGCell and (goRight or goLeft);
// Override.
//goOutsideGCell = !isGlobal() && !isTerminal();
ltrace(200) << "AutoSegment::canGoOutsideGCell() - " << goOutsideGCell << endl;
ltraceout(200);
return goOutsideGCell;
}
bool AutoSegment::canDesalignate ()
{
ltrace(200) << "AutoSegment::canDesalignate()" << endl;
map<AutoContact*,int> innerContacts;
map<AutoContact*,int>::iterator icontact;
getAlignedContacts ( innerContacts );
for ( icontact=innerContacts.begin() ; icontact != innerContacts.end() ; icontact++ ) {
ltrace(200) << "| " << "flags:" << icontact->second
<< " " << (void*)icontact->first->base() << ":" << icontact->first << endl;
if ( (icontact->second & 0x5 ) && canDesalignate(icontact->first) ) return true;
//if ( (icontact->second & 0x3 ) && canDesalignate(icontact->first) ) return true;
//if ( (icontact->second & 0x12) && canDesalignate(icontact->first) ) return true;
}
ltrace(200) << "No AutoContact suitable for desalignment." << endl;
return false;
}
void AutoSegment::desalignate ()
{
map<AutoContact*,int> innerContacts;
map<AutoContact*,int>::iterator icontact;
vector<AutoSegment*> segments;
// Ugly. Must fusion with the inner contact loop.
forEach ( AutoSegment*, isegment, getCollapseds() ) {
segments.push_back ( *isegment );
}
invalidate ();
getAlignedContacts ( innerContacts );
for ( icontact=innerContacts.begin() ; icontact != innerContacts.end() ; icontact++ ) {
desalignate ( icontact->first );
//if ( icontact->second & 0x3 ) desalignate ( icontact->first );
//if ( icontact->second & 0x3 ) desalignate ( icontact->first );
//if ( icontact->second & 0x12) desalignate ( icontact->first );
}
Session::invalidate ( getNet() );
Session::revalidateTopology ();
}
void AutoSegment::changeDepth ( unsigned int depth, bool propagate, bool standAlone )
{
invalidate ();
Session::invalidate ( getNet() );
Session::setInvalidateMask ( Session::NetSplitContacts );
_changeDepth ( depth, true );
if ( propagate ) {
forEach ( AutoSegment*, isegment, getCollapseds() ) {
isegment->_changeDepth ( depth, true );
}
}
if ( standAlone ) Session::revalidateTopology();
}
void AutoSegment::_changeDepth ( unsigned int depth, bool withNeighbors )
{
ltrace(200) << "_changeDepth() - " << this << endl;
ltracein(200);
const Layer* layer0 = Session::getRoutingGauge()->getRoutingLayer(depth);
if ( getLayer() != layer0 ) {
setLayer ( layer0 );
getAutoSource()->invalidate();
getAutoTarget()->invalidate();
}
if ( !withNeighbors ) {
ltraceout(200);
return;
}
forEach ( Component*, icomponent, getAutoSource()->getSlaveComponents() ) {
if ( *icomponent == base() ) continue;
Segment* segment = dynamic_cast<Segment*>(*icomponent);
if ( !segment ) continue;
AutoSegment* autoSegment = Session::lookup ( segment );
if ( !autoSegment ) continue;
if ( autoSegment->isGlobal () ) continue;
if ( autoSegment->isTerminal() ) continue;
if ( !( autoSegment->isHorizontal() xor isHorizontal() ) ) {
autoSegment->_changeDepth ( depth, false );
} else {
autoSegment->_changeDepth ( depth-1, false );
}
}
forEach ( Component*, icomponent, getAutoTarget()->getSlaveComponents() ) {
if ( *icomponent == base() ) continue;
Segment* segment = dynamic_cast<Segment*>(*icomponent);
if ( !segment ) continue;
AutoSegment* autoSegment = Session::lookup ( segment );
if ( !autoSegment ) continue;
if ( autoSegment->isGlobal () ) continue;
if ( autoSegment->isTerminal() ) continue;
if ( !( autoSegment->isHorizontal() xor isHorizontal() ) ) {
autoSegment->_changeDepth ( depth, false );
} else {
autoSegment->_changeDepth ( depth-1, false );
}
}
vector<GCell*> gcells;
getGCells ( gcells );
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
gcells[i]->invalidate ();
}
ltraceout(200);
}
bool AutoSegment::canSlacken ( bool propagate )
{
ltrace(200) << "AutoSegment::canSlacken()" << endl;
if ( !isGlobal() && !propagate ) return false;
if ( _canSlacken() ) return true;
if ( propagate ) {
forEach ( AutoSegment*, isegment, getCollapseds() ) {
if ( isegment->_canSlacken() ) return true;
}
}
return false;
}
void AutoSegment::slacken ( bool propagate )
{
invalidate ();
set<AutoSegment*,AutoSegment::CompareId> collapseds;
collapseds.insert ( this );
if ( propagate ) {
forEach ( AutoSegment*, isegment, getCollapseds() )
collapseds.insert ( *isegment );
}
set<AutoSegment*>::iterator isegment = collapseds.begin();
for ( ; isegment != collapseds.end() ; isegment++ )
(*isegment)->_slacken ();
Session::invalidate ( getNet() );
Session::revalidateTopology ();
}
bool AutoSegment::canPivotUp ( bool propagate, float reserve )
{
ltrace(200) << "AutoSegment::canPivotUp()" << endl;
//if ( isTerminal() ) return false;
size_t depth = Session::getRoutingGauge()->getLayerDepth(getLayer());
if ( depth+2 >= Session::getRoutingGauge()->getDepth() ) return false;
vector<GCell*> gcells;
getGCells ( gcells );
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
if ( !gcells[i]->hasFreeTrack(depth,reserve) ) return false;
}
ltrace(200) << getAutoSource() << endl;
ltrace(200) << getAutoTarget() << endl;
ltrace(200) << "min depths, Segment:" << depth
<< " S:" << getAutoSource()->getMinDepth()
<< " T:" << getAutoTarget()->getMinDepth() << endl;
if ( getAutoSource()->getMinDepth() < depth ) return false;
if ( getAutoTarget()->getMinDepth() < depth ) return false;
if ( not propagate ) {
ltrace(200) << "AutoSegment::canPivotUp() - true [no propagate]" << endl;
return true;
}
if ( propagate ) {
forEach ( AutoSegment*, isegment, getCollapseds() ) {
isegment->getGCells ( gcells );
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
if ( !gcells[i]->hasFreeTrack(depth,reserve) ) return false;
}
if ( isegment->getAutoSource()->getMinDepth() < depth ) return false;
if ( isegment->getAutoTarget()->getMinDepth() < depth ) return false;
}
}
ltrace(200) << "AutoSegment::canPivotUp() - true [propagate]" << endl;
return true;
}
bool AutoSegment::canMoveUp ( bool propagate, float reserve )
{
ltrace(200) << "AutoSegment::canMoveUp()" << endl;
if ( isLayerChange() ) return false;
if ( isTerminal() and isLocal() ) return false;
size_t depth = Session::getRoutingGauge()->getLayerDepth(getLayer()) + 2;
if ( depth >= Session::getConfiguration()->getAllowedDepth() ) return false;
vector<GCell*> gcells;
getGCells ( gcells );
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
if ( not gcells[i]->hasFreeTrack(depth,reserve) ) return false;
}
if ( isLocal() and not propagate ) {
if ( not getAutoSource()->canMoveUp(this) ) return false;
if ( not getAutoTarget()->canMoveUp(this) ) return false;
return true;
}
bool hasGlobalSegment = false;
size_t collapseds = 0;
if ( propagate ) {
forEach ( AutoSegment*, isegment, getCollapseds() ) {
collapseds++;
if ( isegment->isGlobal() ) hasGlobalSegment = true;
isegment->getGCells ( gcells );
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
if ( not gcells[i]->hasFreeTrack(depth,reserve) ) {
ltrace(200) << "Not enough free track in " << gcells[i] << endl;
return false;
}
}
}
}
return true;
}
bool AutoSegment::moveUp ( bool propagate )
{
if ( !canMoveUp(propagate) ) return false;
changeDepth ( Session::getRoutingGauge()->getLayerDepth(getLayer()) + 2, propagate );
return true;
}
bool AutoSegment::canDogLeg ( Interval interval )
{
ltrace(200) << "AutoSegment::canDogLeg(Interval) " << interval << endl;
size_t leftDogleg = 0;
size_t rightDogleg = 0;
if ( getSpanU().contains(interval.getVMin()) ) leftDogleg++;
if ( getSpanU().contains(interval.getVMax()) ) rightDogleg++;
forEach ( AutoSegment*, isegment, getCollapseds() ) {
if ( isegment->getSpanU().contains(interval.getVMin()) ) {
if ( isegment->isFixed() ) return false;
leftDogleg++;
}
if ( isegment->getSpanU().contains(interval.getVMax()) ) {
if ( isegment->isFixed() ) return false;
rightDogleg++;
}
}
if ( (leftDogleg == 1) and (rightDogleg <= 1) ) return true;
if ( (leftDogleg <= 1) and (rightDogleg == 1) ) return true;
ltrace(200) << "leftCount:" << leftDogleg << " rightCount:" << rightDogleg << endl;
return false;
}
void AutoSegment::makeDogLeg ( Interval interval, bool upLayer, bool& leftDogleg )
{
ltrace(200) << "AutoSegment::makeDogLeg(Interval)" << endl;
size_t leftDoglegCount = 0;
size_t rightDoglegCount = 0;
AutoSegment* leftCandidate = NULL;
AutoSegment* rightCandidate = NULL;
if ( getSpanU().contains(interval.getVMin()) ) { leftCandidate = this; leftDoglegCount++; }
if ( getSpanU().contains(interval.getVMax()) ) { rightCandidate = this; rightDoglegCount++; }
forEach ( AutoSegment*, isegment, getCollapseds() ) {
if ( isegment->getSpanU().contains(interval.getVMin()) ) { leftCandidate = *isegment; leftDoglegCount++; }
if ( isegment->getSpanU().contains(interval.getVMax()) ) { rightCandidate = *isegment; rightDoglegCount++; }
}
leftDogleg = true;
if ( (leftDoglegCount != 1) and (rightDoglegCount != 1) ) return;
if ( !leftDoglegCount ) {
leftDogleg = false;
leftCandidate = rightCandidate;
rightCandidate = NULL;
}
if ( leftCandidate && rightCandidate ) {
ltrace(200) << "Left Constraint: " << leftCandidate->getSourceConstraints(true) << endl;
ltrace(200) << "Right Constraint: " << rightCandidate->getTargetConstraints(true) << endl;
if ( leftCandidate ->getTargetConstraints(true).getSize()
< rightCandidate->getSourceConstraints(true).getSize() ) {
leftCandidate = rightCandidate;
leftDogleg = false;
}
} else {
if ( !leftCandidate ) {
leftCandidate = rightCandidate;
leftDogleg = false;
}
}
if ( leftCandidate ) {
leftCandidate->_makeDogLeg ( getAutoSource()->getGCell(), upLayer );
const vector<AutoSegment*>& dogLegs = Session::getDogLegs();
if ( dogLegs.size() >= 2 ) {
DbU::Unit axis;
if ( leftDogleg )
axis = interval.getVMin() - DbU::lambda(5.0); // Ugly: Hard-wired track spacing.
else
axis = interval.getVMax() + DbU::lambda(5.0); // Ugly: Hard-wired track spacing.
ltrace(200) << "AutoSegment::makeDogLeg(): @" << DbU::getValueString(axis) << endl;
dogLegs[1]->setAxis ( axis );
}
}
}
void AutoSegment::makeDogLeg ( GCell* dogLegGCell, bool upLayer )
{
ltrace(160) << "AutoSegment::makeDogLeg(GCell*)" << endl;
ltracein(160);
if ( isFixed() ) {
cerr << Error("AutoSegment::makeDogLeg(): Cannot make a dog leg on a fixed segment.\n"
" (on: %s)",_getString().c_str()) << endl;
return;
}
invalidate ();
if ( dogLegGCell->getUSide(getDirection()).intersect(getSpanU()) ) {
ltrace(159) << "Dogleg in " << this << endl;
_makeDogLeg ( dogLegGCell, upLayer );
//Session::revalidate ( getNet() );
} else {
ltrace(159) << "Looking in aligneds." << endl;
forEach ( AutoSegment*, aligned, getCollapseds() ) {
ltrace(159) << "| Try in " << *aligned << endl;
if ( dogLegGCell->getUSide(getDirection()).intersect(aligned->getSpanU()) ) {
ltrace(159) << "Dogleg in " << *aligned << endl;
aligned->_makeDogLeg ( dogLegGCell, upLayer );
//Session::revalidate ( getNet() );
ltraceout(160);
return;
}
}
cerr << Bug("Cannot make a dogleg in %s at %s"
,_getString().c_str(), getString(dogLegGCell).c_str()) << endl;
}
ltraceout(160);
}
bool AutoSegment::_check () const
{
bool coherency = true;
coherency = coherency && checkInvalidated();
coherency = coherency && checkPositions();
coherency = coherency && checkConstraints();
return coherency;
}
string AutoSegment::_getString () const
{
string s = getSegment()->_getString();
s.insert ( 1, "id: " );
s.insert ( 4, getString(_id) );
s.insert ( s.size()-1, (_isFixed )?" F":" -" );
s.insert ( s.size()-1, (_strap )? "S": "-" );
s.insert ( s.size()-1, (_isCanonical)? "C": "-" );
s.insert ( s.size()-1, (_isCollapsed)? "c": "-" );
s.insert ( s.size()-1, (_isGlobal) ? "g": "-" );
s.insert ( s.size()-1, (_isTerminal) ? "t": "-" );
s.insert ( s.size()-1, (_slackened) ? "S": "-" );
s.insert ( s.size()-1, (_invalidated)? "i": "-" );
return s;
}
Record* AutoSegment::_getRecord () const
{
Record* record = getSegment()->_getRecord ();
record->add ( getSlot ( "_gcell" , _gcell ) );
record->add ( getSlot ( "_isHorizontal" , &_isHorizontal ) );
record->add ( getSlot ( "_isFixed" , &_isFixed ) );
record->add ( getSlot ( "_strap" , &_strap ) );
record->add ( getSlot ( "_layerChange" , &_layerChange ) );
record->add ( getSlot ( "_isCanonical" , &_isCanonical ) );
record->add ( getSlot ( "_isCollapsed" , &_isCollapsed ) );
record->add ( getSlot ( "_isGlobal" , &_isGlobal ) );
record->add ( getSlot ( "_isTerminal" , &_isTerminal ) );
record->add ( getSlot ( "_slackened" , &_slackened ) );
record->add ( getSlot ( "_invalidated" , &_invalidated ) );
record->add ( getSlot ( "_sourcePosition", &_sourcePosition ) );
record->add ( getSlot ( "_targetPosition", &_targetPosition ) );
return record;
}
AutoSegment* AutoSegment::create ( AutoContact* source
, AutoContact* target
, Segment* hurricaneSegment
)
{
static Layer* verticalLayer = DataBase::getDB()->getTechnology()->getLayer ( "METAL3" );
static Layer* horizontalLayer = DataBase::getDB()->getTechnology()->getLayer ( "METAL2" );
AutoSegment* segment;
Horizontal* horizontal;
Vertical* vertical;
Contact* contact = dynamic_cast<Contact*>(hurricaneSegment->getSource());
AutoContact* autoContact = Session::lookup(contact);
if ( contact == NULL ) {
throw Error ( badSegmentSource, getString(hurricaneSegment).c_str() );
if ( autoContact and ( autoContact != source ) )
throw Error ( mismatchSegmentSource
, getString(hurricaneSegment).c_str()
, getString(contact).c_str() );
}
contact = dynamic_cast<Contact*>(hurricaneSegment->getTarget());
autoContact = Session::lookup(contact);
if ( contact == NULL ) {
throw Error ( badSegmentTarget, getString(hurricaneSegment).c_str() );
if ( autoContact and ( autoContact != target ) )
throw Error ( mismatchSegmentTarget
, getString(hurricaneSegment).c_str()
, getString(contact).c_str() );
}
Hook* hook = hurricaneSegment->getSourceHook();
hook->detach ();
hook->attach ( source->getBodyHook() );
hook = hurricaneSegment->getTargetHook();
hook->detach ();
hook->attach ( target->getBodyHook() );
if ( (horizontal = dynamic_cast<Horizontal*>(hurricaneSegment) ) ) {
if ( horizontal->getLayer() != horizontalLayer ) {
if ( !Session::getKatabatic()->isGMetal(horizontal->getLayer()) )
cerr << Warning("Segment %s forced to %s."
,getString(horizontal).c_str()
,getString(horizontalLayer).c_str()) << endl;
horizontal->setLayer ( horizontalLayer );
}
segment = AutoHorizontal::create ( horizontal
, AutoSegment::Global
, false
, false
);
} else if ( (vertical = dynamic_cast<Vertical*>(hurricaneSegment)) ) {
if ( vertical->getLayer() != verticalLayer ) {
if ( !Session::getKatabatic()->isGMetal(vertical->getLayer()) )
cerr << Warning("Segment %s forced to %s."
,getString(vertical).c_str()
,getString(verticalLayer).c_str()) << endl;
vertical->setLayer ( verticalLayer );
}
segment = AutoVertical::create ( vertical
, AutoSegment::Global
, false
, false
);
} else {
throw Error ( badSegment, getString(source).c_str(), getString(target).c_str() );
}
ltrace(99) << "Creating " << segment << endl;
return segment;
}
AutoSegment* AutoSegment::create ( AutoContact* source
, AutoContact* target
, unsigned int dir
, int type
, bool terminal
, bool collapsed
)
{
//static Layer* verticalLayer = DataBase::getDB()->getTechnology()->getLayer ( "METAL3" );
//static Layer* horizontalLayer = DataBase::getDB()->getTechnology()->getLayer ( "METAL2" );
static const Layer* horizontalLayer = Session::getRoutingLayer ( 1 );
static const Layer* verticalLayer = Session::getRoutingLayer ( 2 );
GCell* gcell;
GCell* end;
AutoSegment* segment;
if ( dir & Constant::Horizontal ) {
segment = AutoHorizontal::create ( source
, target
, horizontalLayer
, source->getY()
, DbU::lambda(2.0)
, type
, terminal
, collapsed
);
if ( type == AutoSegment::Global ) {
if ( source->getGCell()->getX() < target->getGCell()->getX() ) {
gcell = source->getGCell()->getRight();
end = target->getGCell();
} else {
gcell = target->getGCell()->getRight();
end = source->getGCell();
}
for ( ; gcell != end ; gcell = gcell->getRight() ) {
if ( !gcell ) {
cerr << Error("AutoSegment::create() : NULL GCell.") << endl;
break;
}
gcell->addHSegment ( segment );
}
}
} else if ( dir & Constant::Vertical ) {
segment = AutoVertical::create ( source
, target
, verticalLayer
, source->getX()
, DbU::lambda(2.0)
, type
, terminal
, collapsed
);
if ( type == AutoSegment::Global ) {
if ( source->getGCell()->getY() < target->getGCell()->getY() ) {
gcell = source->getGCell()->getUp();
end = target->getGCell();
} else {
gcell = target->getGCell()->getUp();
end = source->getGCell();
}
for ( ; gcell != end ; gcell = gcell->getUp() ) {
if ( !gcell ) {
cerr << Error("AutoSegment::create() : NULL GCell.") << endl;
break;
}
gcell->addVSegment ( segment );
}
}
} else
throw Error ( badSegment, getString(source).c_str(), getString(target).c_str() );
ltrace(99) << "create() " << segment << endl;
return segment;
}
void AutoSegment::destroy ()
{
_preDestroy ();
delete this;
}
bool AutoSegment::isTopologicalBound ( AutoSegment* seed
, bool superior
, bool isHorizontal )
{
ltrace(80) << "isTopologicalBound() - " << seed << endl;
ltracein(80);
set<AutoContact*> exploreds;
vector<AutoContact*> stack;
DbU::Unit axis;
if ( superior ) axis = seed->getTargetU();
else axis = seed->getSourceU();
ltrace(80) << "check for bound " << DbU::getValueString(axis) << endl;
exploreds.insert ( seed->getAutoSource() );
exploreds.insert ( seed->getAutoTarget() );
if ( seed->getLength() ) {
if ( superior ) stack.push_back ( seed->getAutoTarget() );
else stack.push_back ( seed->getAutoSource() );
} else {
stack.push_back ( seed->getAutoTarget() );
stack.push_back ( seed->getAutoSource() );
}
while ( !stack.empty() ) {
AutoContact* currentContact = stack.back();
stack.pop_back ();
ltrace(80) << "Exploring: " << (void*)currentContact
<< " " << currentContact << endl;
exploreds.insert ( currentContact );
if ( currentContact->getAnchor() ) { ltraceout(80); return true; }
forEach ( Component*, component, currentContact->getSlaveComponents() ) {
Segment* segment = dynamic_cast<Segment*>(*component);
if ( !segment ) continue;
AutoSegment* autoSegment = Session::lookup ( segment );
if ( !autoSegment ) continue;
if ( !autoSegment->getLength() ) {
AutoContact* contact = autoSegment->getAutoSource();
if ( contact && ( contact != currentContact ) ) {
if ( exploreds.find(contact) == exploreds.end() )
stack.push_back ( contact );
}
contact = autoSegment->getAutoTarget();
if ( contact && ( contact != currentContact ) ) {
if ( exploreds.find(contact) == exploreds.end() )
stack.push_back ( contact );
}
continue;
}
if ( autoSegment->isHorizontal() != isHorizontal ) continue;
ltrace(80) << "| " << autoSegment << endl;
if ( superior ) {
if ( autoSegment->getTargetU() > axis ) { ltraceout(80); return true; }
} else {
if ( autoSegment->getSourceU() < axis ) { ltraceout(80); return true; }
}
}
}
ltraceout(80);
return false;
}
unsigned int AutoSegment::getPerpandicularState ( AutoContact* contact
, AutoSegment* source
, AutoSegment* current
, bool isHorizontalMaster
, const Layer* masterLayer )
{
unsigned int state = 0;
bool sourcePerpandicular = arePerpandiculars ( isHorizontalMaster, source );
bool currentPerpandicular = arePerpandiculars ( isHorizontalMaster, current );
bool contactAlignate
= (contact->isHAlignate() and current->isHorizontal() and isHorizontalMaster)
or (contact->isVAlignate() and !current->isHorizontal() and !isHorizontalMaster);
if ( not currentPerpandicular and masterLayer and (masterLayer != current->getLayer()) )
state |= ParallelAndLayerChange;
if ( currentPerpandicular and !current->isCollapsed() )
state |= PerpandicularAny;
if ( sourcePerpandicular ) {
// Source segment is perpandicular to master.
if ( currentPerpandicular and !current->isCollapsed() )
state |= PerpandicularIndirect;
} else {
// Source segment is parallel to master.
if ( not (currentPerpandicular and current->isCollapsed()) and not contactAlignate ) {
// Current segment is parallel OR expanded.
state |= ParallelOrExpanded;
}
}
return state;
}
void AutoSegment::getTopologicalInfos ( AutoSegment* seed
, vector<AutoSegment*>& collapseds
, vector<AutoSegment*>& perpandiculars
, DbU::Unit& leftBound
, DbU::Unit& rightBound
)
{
ltrace(80) << "getTopologicalInfos() - " << seed << endl;
leftBound = DbU::Max;
rightBound = DbU::Min;
AutoSegmentStack stack;
stack.push ( seed->getAutoSource(), seed );
stack.push ( seed->getAutoTarget(), seed );
while ( !stack.isEmpty() ) {
AutoContact* sourceContact = stack.getAutoContact ();
AutoSegment* sourceSegment = stack.getAutoSegment ();
stack.pop ();
DbU::Unit constraint;
if ( seed->isHorizontal() ) constraint = sourceContact->getCBXMax();
else constraint = sourceContact->getCBYMax();
if ( constraint < leftBound ) leftBound = constraint;
if ( seed->isHorizontal() ) constraint = sourceContact->getCBXMin();
else constraint = sourceContact->getCBYMin();
if ( constraint > rightBound ) rightBound = constraint;
forEach ( Component*, component, sourceContact->getSlaveComponents() ) {
Segment* segment = dynamic_cast<Segment*>(*component);
if ( ( !segment ) || ( segment == sourceSegment->getSegment() ) ) continue;
AutoSegment* currentSegment = Session::lookup ( segment );
if ( !currentSegment ) {
cerr << Error("Can't lookup <AutoSegment> for %s.",getString(segment).c_str()) << endl;
continue;
}
unsigned int state = getPerpandicularState ( sourceContact
, sourceSegment
, currentSegment
, seed );
if ( state & PerpandicularAny ) {
ltrace(79) << "Perpandicular: " << currentSegment << endl;
perpandiculars.push_back ( currentSegment );
}
if ( state & (PerpandicularIndirect
|ParallelOrExpanded
|ParallelAndLayerChange ) ) {
ltrace(79) << "Reject: " << currentSegment << endl;
continue;
}
if ( !areAligneds(currentSegment,seed) ) {
collapseds.push_back ( currentSegment );
ltrace(79) << "collapsed: " << currentSegment << endl;
}
Component* opposite = segment->getOppositeAnchor ( sourceContact->getContact() );
AutoContact* targetContact = Session::lookup(static_cast<Contact*>(opposite));
if ( targetContact ) stack.push ( targetContact, currentSegment );
}
}
}
int AutoSegment::getTerminalCount ( AutoSegment* seed, vector<AutoSegment*>& collapseds )
{
ltrace(80) << "getTerminalCount() - " << seed << " (+collapseds)" << endl;
int count = 0;
for ( size_t i=0 ; i < collapseds.size() ; i++ ) {
if ( collapseds[i]->isTerminal() )
count++;
}
if ( seed->getAutoSource()->isTerminal() ) count++;
if ( seed->getAutoTarget()->isTerminal() ) count++;
return count;
}
} // End of Katabatic namespace.