20 #include <QApplication>
21 #include <QElapsedTimer>
26 template<
typename T1,
typename T2>
27 static void storeMax(
QMap<T1, T2>& map, T1 key, T2 value)
30 if (map.
value(key) >= value)
36 const static qreal sLaneSpacing = 10;
37 const static qreal sHRoadPadding = 10;
38 const static qreal sVRoadPadding = 10;
39 const static qreal sMinimumVChannelWidth = 20;
40 const static qreal sMinimumHChannelHeight = 20;
43 :
QObject(parent), mScene(new
GraphicsScene(this)), mParentContext(context), mDone(false), mRollbackStatus(0), mDumpJunctions(false)
73 retval->
insert(it.key(),it.value());
93 xout <<
"Node positions " << search.
x() <<
" " << search.
y() <<
"\n";
98 xout << (it.key() == search ?
"*" :
" ") << it.key().x() << it.key().y() << (it.value().type() ==
Node::Module ?
"M" :
"G") << it.value().id() <<
"\n";
120 --positionOccupied[jt.value()];
121 ++positionOccupied[it.value()];
122 jt.
value() = it.value();
126 for (
auto rpit = positionOccupied.
begin(); rpit != positionOccupied.
end(); ++rpit)
127 if (rpit.value() < 0)
172 QPoint retval(INT_MIN, INT_MIN);
178 return QPoint(nbox->
x(), nbox->
y());
208 return mMaxNodeWidth;
213 return mMaxNodeHeight;
218 return mMaxNodeWidth + sMinimumVChannelWidth;
223 return mMaxNodeHeight + sMinimumHChannelHeight;
229 int inx = ix - mMinXIndex;
232 if (inx < mXValues.
size())
233 return mXValues[inx];
240 int inx = iy - mMinYIndex;
243 if (inx < mYValues.
size())
244 return mYValues[inx];
264 findMaxBoxDimensions();
266 findMaxChannelLanes();
268 calculateJunctionMinDistance();
270 calculateGateOffsets();
273 mCoordArrayX =
new SceneCoordinateArray(mCoordX);
274 mCoordArrayY =
new SceneCoordinateArray(mCoordY);
285 #ifdef GUI_DEBUG_GRID
290 qDebug() <<
"elapsed time (experimental new) layout [ms]" << timer.
elapsed();
312 mRollbackStatus = -1;
321 void GraphLayouter::clearComments()
328 mCommentBubbles.clear();
331 void GraphLayouter::clearLayoutData()
338 mMaxNodeWidthForX.
clear();
339 mMaxNodeHeightForY.
clear();
341 mNodeOffsetForX.
clear();
342 mNodeOffsetForY.
clear();
344 mMaxLeftIoPaddingForChannelX.
clear();
345 mMaxRightIoPaddingForChannelX.
clear();
347 mMinXIndex = INT_MAX;
348 mMinYIndex = INT_MAX;
350 mMaxXIndex = INT_MIN;
351 mMaxYIndex = INT_MIN;
361 mEndpointHash.clear();
363 mJunctionEntries.clear();
364 mSeparatedWidth.clear();
367 mJunctionMinDistanceY.
clear();
368 mWireEndpoint.
clear();
369 mGlobalInputHash.
clear();
370 mGlobalOutputHash.
clear();
371 mNodeBoundingBox =
QRect();
378 void GraphLayouter::createBoxes()
381 int xmin, xmax, ymin, ymax;
382 xmin = ymin = xmax = ymax = 0;
388 if (first || x + 1 > xmax)
390 if (first || y + 1 > ymax)
392 if (first || x < xmin)
394 if (first || y < ymin)
400 mNodeBoundingBox =
QRect(xmin, ymin, xmax - xmin, ymax - ymin);
403 bool GraphLayouter::verifyModulePort(Net*
n,
const Node& modNode,
bool isModInput)
413 if (std::unordered_set<Net*> nets = m->get_input_nets(); nets.find(
n) != nets.end())
420 if (std::unordered_set<Net*> nets = m->get_output_nets(); nets.find(
n) != nets.end())
429 void GraphLayouter::handleCommentAboutToDeleted(CommentEntry* entry)
438 void GraphLayouter::handleCommentAdded(CommentEntry* entry)
447 void GraphLayouter::getWireHash()
459 mWireEndpoint[
id] = EndpointList();
461 for (
const Endpoint* src :
n->get_sources())
464 const NodeBox* srcBox = mBoxes.
boxForGate(src->get_gate());
468 mViewInput.
insert(
n->get_id());
472 if (!verifyModulePort(
n, srcBox->getNode(),
false))
475 NetLayoutPoint srcPnt(srcBox->x() + 1, 2 * srcBox->y());
477 mWireEndpoint[
id].addSource(srcPnt);
480 for (
const Endpoint* dst :
n->get_destinations())
483 const NodeBox* dstBox = mBoxes.
boxForGate(dst->get_gate());
487 mViewOutput.
insert(
n->get_id());
491 if (!verifyModulePort(
n, dstBox->getNode(),
true))
494 NetLayoutPoint dstPnt(dstBox->x(), 2 * dstBox->y());
496 mWireEndpoint[
id].addDestination(dstPnt);
500 mWireEndpoint[
id].setNetType(EndpointList::ConstantLevel);
503 EndpointList::EndpointType nType = mWireEndpoint.
value(
id).netType();
504 if ((nType == EndpointList::SingleDestination && dstPoints.
size() > 1) || (nType == EndpointList::SourceAndDestination && mViewInput.
contains(
n->get_id())))
507 int ypos = mGlobalInputHash.
size();
508 NetLayoutPoint srcPnt(mNodeBoundingBox.
left(), 2 * ypos);
510 mWireEndpoint[
id].addSource(srcPnt);
511 mGlobalInputHash[
id] = ypos;
512 mWireEndpoint[
id].setNetType(EndpointList::HasGlobalEndpoint);
513 mWireEndpoint[
id].setInputArrow();
516 if ((nType == EndpointList::SingleSource && srcPoints.
size() > 1) || (nType == EndpointList::SourceAndDestination && mViewOutput.
contains(
n->get_id())))
519 int ypos = mGlobalOutputHash.
size();
520 NetLayoutPoint dstPnt(mNodeBoundingBox.
right() + 1, 2 * ypos);
522 mWireEndpoint[
id].addDestination(dstPnt);
523 mGlobalOutputHash[
id] = ypos;
524 mWireEndpoint[
id].setNetType(EndpointList::HasGlobalEndpoint);
525 mWireEndpoint[
id].setOutputArrow();
528 const EndpointList& epl = mWireEndpoint.
value(
id);
529 switch (epl.netType())
531 case EndpointList::SingleSource:
532 case EndpointList::SingleDestination:
533 case EndpointList::ConstantLevel: {
535 for (
const NetLayoutPoint& pnt : epl)
537 bool isInput = epl.isInput(ipnt++);
538 SeparatedGraphicsNet* net_item = epl.netType() == EndpointList::ConstantLevel
540 :
static_cast<SeparatedGraphicsNet*
>(
new ArrowSeparatedNet(
n));
542 mSeparatedWidth[pnt].requireInputSpace(net_item->inputWidth() + sLaneSpacing);
547 mSeparatedWidth[pnt].requireOutputSpace(nb->item()->width() + net_item->outputWidth() + sLaneSpacing);
553 case EndpointList::SourceAndDestination:
554 case EndpointList::HasGlobalEndpoint:
556 NetLayoutConnectionFactory nlcf(srcPoints.
toList(), dstPoints.
toList());
558 mConnectionMetric.
insert(NetLayoutMetric(
id, nlcf.connection), nlcf.connection);
567 for (
auto it = mConnectionMetric.
constBegin(); it != mConnectionMetric.
constEnd(); ++it)
569 u32 id = it.
key().getId();
570 const NetLayoutConnection* nlc = it.value();
571 for (
const NetLayoutWire& w : *nlc)
573 mWireHash[w].append(
id);
578 for (
auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it)
580 for (
int iend = 0; iend < 2; iend++)
585 mJunctionEntries[pnt].mEntries[idirBase + iend] = it.value();
590 for (
const NodeBox* nbox : mBoxes)
592 NetLayoutPoint inPnt(nbox->x(), nbox->y() * 2);
593 QList<u32> inpNets = nbox->item()->inputNets();
595 mEndpointHash[inPnt].setInputPins(nbox->item()->inputNets(), nbox->item()->yTopPinDistance(), nbox->item()->yEndpointDistance());
596 NetLayoutPoint outPnt(nbox->x() + 1, nbox->y() * 2);
598 mEndpointHash[outPnt].setOutputPins(nbox->item()->outputNets(), nbox->item()->yTopPinDistance(), nbox->item()->yEndpointDistance());
601 for (
auto itGlInp = mGlobalInputHash.
constBegin(); itGlInp != mGlobalInputHash.
constEnd(); ++itGlInp)
604 netIds.
append(itGlInp.key());
605 NetLayoutPoint pnt(mNodeBoundingBox.
left(), 2 * itGlInp.value());
607 if (!mEndpointHash.contains(pnt))
608 mEndpointHash[pnt].setOutputPins(netIds, 0, 0);
611 for (
auto itGlOut = mGlobalOutputHash.
constBegin(); itGlOut != mGlobalOutputHash.
constEnd(); ++itGlOut)
614 netIds.
append(itGlOut.key());
615 NetLayoutPoint pnt(mNodeBoundingBox.
right() + 1, 2 * itGlOut.value());
617 if (!mEndpointHash.contains(pnt))
618 mEndpointHash[pnt].setInputPins(netIds, 0, 0);
621 auto it = mJunctionEntries.constBegin();
622 while (it != mJunctionEntries.constEnd() || !mJunctionThreads.isEmpty())
626 if (!it.value().isTrivial())
629 it.value().dumpToFile(it.key());
630 JunctionThread* jt =
new JunctionThread(it.key(), it.value());
632 mJunctionThreads.append(jt);
637 qApp->processEvents();
641 void GraphLayouter::findMaxBoxDimensions()
643 for (
const NodeBox* box : mBoxes)
645 if (box->x() < mMinXIndex)
646 mMinXIndex = box->x();
647 else if (box->x() > mMaxXIndex)
648 mMaxXIndex = box->x();
650 if (box->y() < mMinYIndex)
651 mMinYIndex = box->y();
652 else if (box->y() > mMaxYIndex)
653 mMaxYIndex = box->y();
655 if (mMaxNodeWidth < box->item()->width())
656 mMaxNodeWidth = box->item()->width();
658 if (mMaxNodeHeight < box->item()->height())
659 mMaxNodeHeight = box->item()->height();
661 storeMax(mMaxNodeWidthForX, box->x(), box->item()->width());
662 storeMax(mMaxNodeHeightForY, box->y(), box->item()->height());
664 storeMax(mMaxRightIoPaddingForChannelX, box->x(), box->inputPadding());
665 storeMax(mMaxLeftIoPaddingForChannelX, box->x() + 1, box->outputPadding());
669 void GraphLayouter::findMaxChannelLanes()
672 for (
auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it)
675 unsigned int nw = it.value().size();
676 if (it.key().isHorizontal())
677 mCoordY[pnt.y()].testMinMax(nw);
679 mCoordX[pnt.x()].testMinMax(nw);
685 const NetLayoutPoint& pnt = it.
key();
686 const QRect& rect = it.value()->rect();
687 mCoordX[pnt.x()].testMinMax(rect.
left());
688 mCoordX[pnt.x()].testMinMax(rect.
right());
689 mCoordY[pnt.y()].testMinMax(rect.
top());
690 mCoordY[pnt.y()].testMinMax(rect.
bottom());
695 mCoordX[mNodeBoundingBox.
left()].testMinMax(0);
697 mCoordY[mNodeBoundingBox.
top()].testMinMax(0);
702 auto itx0 = mCoordX.
begin();
703 for (
auto itx1 = itx0 + 1; itx1 != mCoordX.
end(); ++itx1)
705 for (
int x = itx0.key() + 1; x < itx1.key(); x++)
706 mCoordX[x].testMinMax(0);
712 auto ity0 = mCoordY.
begin();
713 for (
auto ity1 = ity0 + 1; ity1 != mCoordY.
end(); ++ity1)
715 for (
int y = ity0.key() + 1; y < ity1.key(); y++)
716 mCoordY[y].testMinMax(0);
722 void GraphLayouter::calculateJunctionMinDistance()
724 for (
auto itJun = mJunctionHash.
constBegin(); itJun != mJunctionHash.
constEnd(); ++itJun)
726 const NetLayoutPoint& pnt0 = itJun.
key();
727 NetLayoutPoint pnt1 = pnt0 +
QPoint(0, 1);
728 const NetLayoutJunction* j1 = mJunctionHash.
value(pnt1);
731 const NetLayoutJunction* j0 = itJun.value();
732 auto itEdp = mEndpointHash.find(pnt1.isEndpoint() ? pnt1 : pnt0);
733 if (itEdp == mEndpointHash.constEnd())
735 float minDistance = 0;
737 if (pnt1.isEndpoint())
740 minDistance = (j0->rect().bottom() + 1) * sLaneSpacing - itEdp.value().lanePosition(j1->rect().top(),
false);
745 minDistance = itEdp.value().lanePosition(j0->rect().bottom(),
false) + (1 - j1->rect().top()) * sLaneSpacing;
747 if (minDistance > mJunctionMinDistanceY[iy])
748 mJunctionMinDistanceY[iy] = minDistance;
752 void GraphLayouter::calculateGateOffsets()
756 for (
auto itSep = mSeparatedWidth.constBegin(); itSep != mSeparatedWidth.constEnd(); itSep++)
758 NetLayoutJunction* jx = mJunctionHash.
value(itSep.key());
761 int ix = itSep.key().x();
762 float xinp = jx->rect().right() * sLaneSpacing + itSep.value().mInputSpace;
763 float xout = itSep.value().mOutputSpace - jx->rect().left() * sLaneSpacing;
764 if (xinp > xInputPadding[ix])
765 xInputPadding[ix] = xinp;
766 if (xout > xOutputPadding[ix])
767 xOutputPadding[ix] = xout;
770 int ix0 = mNodeBoundingBox.
x();
772 float x0 = mCoordX[ix0].preLanes() * sLaneSpacing + sHRoadPadding;
773 if (!mGlobalInputHash.
isEmpty())
775 mCoordX[ix0].setOffset(x0);
776 mCoordX[ix0].setPadding(xInputPadding[ix0]);
780 auto itxLast = mCoordX.
begin();
781 for (
auto itNext = itxLast + 1; itNext != mCoordX.
end(); ++itNext)
784 int ix1 = itNext.key();
788 for (
int ix = ix0; ix < ix1; ix++)
790 auto xn = mMaxNodeWidthForX.
find(ix);
791 if (xn != mMaxNodeWidthForX.
end())
794 itNext->setOffsetX(itxLast.value(), xsum + 2 * sHRoadPadding, xOutputPadding[ix1], xInputPadding[ix1]);
795 mXValues.
append(itNext.value().xBoxOffset());
799 int iy0 = mNodeBoundingBox.
y() * 2;
800 float y0 = mCoordY[iy0].preLanes() * sLaneSpacing + sVRoadPadding;
801 mCoordY[iy0].setOffset(y0);
802 auto ityLast = mCoordY.
begin();
803 for (
auto itNext = ityLast + 1; itNext != mCoordY.
end(); ++itNext)
806 int iy1 = itNext.key();
811 itNext->setOffsetYje(ityLast.value(), mJunctionMinDistanceY.
value(iy1));
816 float ydelta = sVRoadPadding;
817 auto yn = mMaxNodeHeightForY.
find(iy0 / 2);
818 if (yn != mMaxNodeHeightForY.
constEnd())
819 ydelta += yn.
value();
820 itNext->setOffsetYej(ityLast.value(), ydelta, mJunctionMinDistanceY.
value(iy1));
825 iy0 = mNodeBoundingBox.
y() * 2;
826 auto ity = mCoordY.
find(iy0);
827 while(ity != mCoordY.
end())
829 mYValues.
append(ity.value().lanePosition(0));
831 ity = mCoordY.
find(iy0);
835 void GraphLayouter::placeGates()
837 for (
const NodeBox* box : mBoxes)
839 box->item()->setPos(mCoordX[box->x()].xBoxOffset(), mCoordY[box->y() * 2].lanePosition(0));
842 NetLayoutPoint outPnt(box->x() + 1, box->y() * 2);
843 QPointF outPos = box->item()->endpointPositionByIndex(0,
false);
844 mEndpointHash[outPnt].setOutputPosition(outPos);
846 NetLayoutPoint inPnt(box->x(), box->y() * 2);
847 QPointF inPos = box->item()->endpointPositionByIndex(0,
true);
848 mEndpointHash[inPnt].setInputPosition(inPos);
852 for (
auto itEp = mEndpointHash.begin(); itEp != mEndpointHash.end(); ++itEp)
854 if (itEp.value().lanePosition(0,
true) <= 0)
856 float px = mCoordX[itEp.key().x()].lanePosition(-1);
857 float py = mCoordY[itEp.key().y()].lanePosition(0);
858 itEp->setOutputPosition(
QPointF(px, py));
863 void GraphLayouter::drawComments()
865 for (NodeBox* box : mBoxes)
869 CommentSpeechBubble* csb =
new CommentSpeechBubble(
QString(
"%1 [%2]").arg(ce->getHeader()).
arg(ce->getCreationTime().toString(
"dd.MM.yy")),
871 QPointF pos = box->item()->pos() +
QPointF(box->item()->width(),0);
873 mCommentBubbles.append(csb);
878 void GraphLayouter::drawNets()
882 for (
auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it)
885 for (
u32 id : it.value())
886 mLaneMap[
id].insert(it.key(), ilane++);
890 int percentCount = netCount / 93;
898 enum LoopState { LoopInit, CanStartThread, WaitForSlot, WaitForLastThread, LoopDone } loopState = LoopInit;
899 while (loopState != LoopDone)
901 if (mNetIterator != mNetsToDraw.
constEnd())
904 loopState = CanStartThread;
906 loopState = WaitForSlot;
910 if (mDrawNetThreads.isEmpty())
911 loopState = LoopDone;
913 loopState = WaitForLastThread;
916 if (loopState == LoopDone)
919 if (loopState == WaitForLastThread || loopState == WaitForSlot)
921 qApp->processEvents();
925 Q_ASSERT(loopState == CanStartThread);
926 u32 id = *(mNetIterator++);
932 const EndpointList& epl = mWireEndpoint.
value(
id);
933 bool regularNet =
false;
935 switch (epl.netType())
937 case EndpointList::NoEndpoint:
940 case EndpointList::SingleSource:
941 case EndpointList::SingleDestination:
942 case EndpointList::ConstantLevel:
944 drawNetsIsolated(
id,
n, epl);
958 if (doneCount % percentCount == 0)
966 mDrawNetThreads.append(dnt);
971 void GraphLayouter::handleJunctionThreadFinished()
973 JunctionThread* jt =
static_cast<JunctionThread*
>(
sender());
974 mJunctionHash.
insert(jt->mNetLayoutPoint,jt->mJunction);
975 mJunctionThreads.removeAll(jt);
979 void GraphLayouter::handleDrawNetThreadFinished()
983 const EndpointList& epl = mWireEndpoint.
value(dnt->id());
985 GraphicsNet* graphicsNet =
nullptr;
986 switch (epl.netType())
988 case EndpointList::HasGlobalEndpoint:
989 if (epl.hasInputArrow())
991 StandardArrowNet* san =
new StandardArrowNet(
n, dnt->mLines, dnt->mKnots);
993 int yGridPos = mGlobalInputHash.
value(dnt->id(), -1);
994 Q_ASSERT(yGridPos >= 0);
995 QPoint pnt(mNodeBoundingBox.
left(), yGridPos * 2);
996 const EndpointCoordinate& epc = mEndpointHash.value(pnt);
997 const NetLayoutJunction* nlj = mJunctionHash.
value(pnt);
998 san->setInputPosition(
QPointF(mCoordArrayX->lanePosition(mNodeBoundingBox.
left(),nlj?nlj->rect().left():0), epc.lanePosition(0,
true)));
1000 if (epl.hasOutputArrow())
1003 StandardArrowNet* san =
new StandardArrowNet(
n, dnt->mLines, dnt->mKnots);
1005 int yGridPos = mGlobalOutputHash.
value(dnt->id(), -1);
1006 Q_ASSERT(yGridPos >= 0);
1007 QPoint pnt(mNodeBoundingBox.
right() + 1, yGridPos * 2);
1008 const EndpointCoordinate& epc = mEndpointHash.value(pnt);
1009 const NetLayoutJunction* nlj = mJunctionHash.
value(pnt);
1010 san->setOutputPosition(
QPointF(mCoordArrayX->lanePosition(pnt.x(),nlj?nlj->rect().right():0), epc.lanePosition(0,
true)));
1013 case EndpointList::SourceAndDestination:
1014 if (dnt->mLines.nLines() > 0)
1015 graphicsNet =
new StandardGraphicsNet(
n, dnt->mLines, dnt->mKnots);
1025 mDrawNetThreads.removeAll(dnt);
1029 void GraphLayouter::drawNetsIsolated(
u32 id, Net*
n,
const EndpointList& epl)
1031 SeparatedGraphicsNet* net_item = epl.netType() == EndpointList::ConstantLevel ?
static_cast<SeparatedGraphicsNet*
>(
new LabeledSeparatedNet(
n,
QString::fromStdString(
n->get_name())))
1032 :
static_cast<SeparatedGraphicsNet*
>(
new ArrowSeparatedNet(
n));
1035 for (
const NetLayoutPoint& pnt : epl)
1037 bool isInput = epl.isInput(ipnt++);
1038 auto itPnt = mEndpointHash.find(pnt);
1039 Q_ASSERT(itPnt != mEndpointHash.constEnd());
1043 const NodeBox* nbox = mBoxes.boxForPoint(pnt.gridPoint());
1045 QList<u32> inpList = nbox->item()->inputNets();
1046 for (
int jnx = 0; jnx < inpList.
size(); jnx++)
1048 u32 inpNetId = inpList.
at(jnx);
1051 QPointF inpPnt(itPnt.value().xInput(), itPnt.value().lanePosition(jnx,
true));
1052 net_item->addInput(inpPnt);
1057 for (
int inx : itPnt.value().outputPinIndex(
id))
1059 QPointF outPnt(itPnt.value().xOutput(), itPnt.value().lanePosition(inx,
true));
1060 net_item->addOutput(outPnt);
1064 net_item->finalize();
1068 void GraphLayouter::updateSceneRect()
1074 rect.
adjust(-200, -200, 200, 200);
1078 bool GraphLayouter::boxExists(
const int x,
const int y)
const
1080 return mBoxes.boxForPoint(
QPoint(x, y)) !=
nullptr;
1083 bool GraphLayouter::hRoadJumpPossible(
const int x,
const int y1,
const int y2)
const
1089 int difference = y1 - y2;
1094 difference = y2 - y1;
1099 if (boxExists(x, bottom_y - difference))
1108 bool GraphLayouter::hRoadJumpPossible(
const GraphLayouter::Road*
const r1,
const GraphLayouter::Road*
const r2)
const
1112 assert(r1->x != r2->x);
1114 return hRoadJumpPossible(r1->x, r1->y, r2->y);
1117 bool GraphLayouter::vRoadJumpPossible(
const int x1,
const int x2,
const int y)
const
1123 int difference = x1 - x2;
1128 difference = x2 - x1;
1133 if (boxExists(right_x - difference, y))
1142 bool GraphLayouter::vRoadJumpPossible(
const GraphLayouter::Road*
const r1,
const GraphLayouter::Road*
const r2)
const
1146 assert(r1->y != r2->y);
1148 return vRoadJumpPossible(r1->x, r2->x, r1->y);
1151 qreal GraphLayouter::hRoadHeight(
const unsigned int mLanes)
const
1154 qreal height = sHRoadPadding * 2;
1157 height += (mLanes - 1) * sLaneSpacing;
1162 qreal GraphLayouter::vRoadWidth(
const unsigned int mLanes)
const
1165 qreal width = sVRoadPadding * 2;
1168 width += (mLanes - 1) * sLaneSpacing;
1173 void GraphLayouter::SceneCoordinate::testMinMax(
int ilane)
1175 if (ilane < minLane)
1177 if (ilane + 1 > maxLane)
1178 maxLane = ilane + 1;
1181 void GraphLayouter::SceneCoordinate::setOffsetX(
const SceneCoordinate& previous,
float maximumBlock,
float sepOut,
float sepInp)
1183 float delta = maximumBlock;
1186 mOffset = previous.xBoxOffset() + (1 - minLane) * sLaneSpacing + delta;
1187 float xDefaultBoxPadding = maxLane * sLaneSpacing;
1188 if (xDefaultBoxPadding < sepInp)
1189 mPadding = sepInp - xDefaultBoxPadding;
1192 void GraphLayouter::SceneCoordinate::setOffsetYje(
const SceneCoordinate& previous,
float minimumJunction)
1194 float delta = (previous.maxLane) * sLaneSpacing + sVRoadPadding;
1195 if (delta < minimumJunction)
1196 delta = minimumJunction;
1197 mOffset = previous.mOffset + delta;
1200 void GraphLayouter::SceneCoordinate::setOffsetYej(
const SceneCoordinate& previous,
float maximumBlock,
float minimumJunction)
1202 float delta = (-minLane - 1) * sLaneSpacing + maximumBlock + sVRoadPadding;
1203 if (delta < minimumJunction)
1204 delta = minimumJunction;
1205 mOffset = previous.mOffset + delta;
1208 float GraphLayouter::SceneCoordinate::lanePosition(
int ilane)
const
1210 return mOffset + ilane * sLaneSpacing;
1213 float GraphLayouter::SceneCoordinate::xBoxOffset()
const
1215 return junctionExit() + sHRoadPadding + mPadding;
1219 : mArray(nullptr), mFirstIndex(0)
1223 mArray =
new float[inputMap.
size()];
1225 mFirstIndex = it.
key();
1226 for (
int i = 0; it != inputMap.
constEnd(); ++it)
1228 mArray[i++] = it.value().lanePosition(0);
1233 GraphLayouter::SceneCoordinateArray::~SceneCoordinateArray()
1235 if (mArray)
delete [] mArray;
1238 float GraphLayouter::SceneCoordinateArray::lanePosition(
int igrid,
int ilane)
const
1240 return mArray[igrid-mFirstIndex] + ilane * sLaneSpacing;
1243 float GraphLayouter::EndpointCoordinate::lanePosition(
int ilane,
bool absolute)
const
1245 float y0 = absolute ? mYoffset : mTopPin;
1247 return y0 + ilane * sLaneSpacing;
1248 int n = numberPins() - 1;
1250 return y0 + ilane * mPinDistance;
1251 return y0 +
n * mPinDistance + (ilane -
n) * sLaneSpacing;
1254 GraphLayouter::EndpointCoordinate::EndpointCoordinate() : mYoffset(0), mXoutput(0), mXinput(0), mPinDistance(0), mTopPin(0), mNumberPins(0)
1259 int GraphLayouter::EndpointCoordinate::numberPins()
const
1264 void GraphLayouter::EndpointCoordinate::setInputPosition(
QPointF p0pos)
1266 mXinput = p0pos.
x();
1267 mYoffset = p0pos.
y();
1270 void GraphLayouter::EndpointCoordinate::setOutputPosition(
QPointF p0pos)
1272 mXoutput = p0pos.
x();
1273 if (mXinput < mXoutput)
1275 mYoffset = p0pos.
y();
1278 QList<int> GraphLayouter::EndpointCoordinate::inputPinIndex(
u32 id)
const
1280 return mInputHash.values(
id);
1283 QList<int> GraphLayouter::EndpointCoordinate::outputPinIndex(
u32 id)
const
1285 return mOutputHash.values(
id);
1288 void GraphLayouter::EndpointCoordinate::setInputPins(
const QList<u32>& pinList,
float p0dist,
float pdist)
1290 int n = pinList.
size();
1291 if (
n > mNumberPins)
1293 for (
int i = 0; i <
n; i++)
1295 u32 id = pinList.
at(i);
1297 mInputHash.insert(
id, i);
1299 if (p0dist > mTopPin)
1301 mPinDistance = pdist;
1304 void GraphLayouter::EndpointCoordinate::setOutputPins(
const QList<u32>& pinList,
float p0dist,
float pdist)
1306 int n = pinList.
size();
1307 if (
n > mNumberPins)
1309 for (
int i = 0; i <
n; i++)
1311 u32 id = pinList.
at(i);
1313 mOutputHash.insert(
id, i);
1315 if (p0dist > mTopPin)
1317 mPinDistance = pdist;
1320 void GraphLayouter::EndpointList::addSource(
const NetLayoutPoint& pnt)
1322 mNetType =
static_cast<EndpointType
>(mNetType | SingleSource);
1323 int existingIndex = indexOf(pnt);
1324 if (existingIndex >= 0 && !mPointIsInput.at(existingIndex))
1327 mPointIsInput.append(
false);
1330 void GraphLayouter::EndpointList::addDestination(
const NetLayoutPoint& pnt)
1332 mNetType =
static_cast<EndpointType
>(mNetType | SingleDestination);
1333 int existingIndex = indexOf(pnt);
1334 if (existingIndex >= 0 && mPointIsInput.at(existingIndex))
1337 mPointIsInput.append(
true);
1340 void GraphLayouter::SeparatedNetWidth::requireInputSpace(
float spc)
1342 if (spc > mInputSpace)
1346 void GraphLayouter::SeparatedNetWidth::requireOutputSpace(
float spc)
1348 if (spc > mOutputSpace)
1352 bool GraphLayouter::isConstNet(
const Net*
n)
1354 for (Endpoint* src :
n->get_sources())
1356 if (src->get_gate()->is_gnd_gate() || src->get_gate()->is_vcc_gate())
1364 return mDumpJunctions;
1369 mDumpJunctions = enabled;
1390 int ilane = it.value();
1391 int ix0 = wFromPoint.
x();
1392 int iy0 = wFromPoint.
y();
1393 int ix1 = wToPoint.
x();
1394 int iy1 = wToPoint.
y();
1396 if (it.key().isHorizontal())
1398 float x0 = mLayouter->mCoordArrayX->lanePosition(ix0,j0? j0->
rect().
right() : 0);
1399 float x1 = mLayouter->mCoordArrayX->lanePosition(ix1,j1? j1->
rect().
left() : 0);
1400 float yy = mLayouter->mCoordArrayY->lanePosition(iy0,ilane);
1406 float xx = mLayouter->mCoordArrayX->lanePosition(ix0,ilane);
1410 auto itEpc = mLayouter->mEndpointHash.find(wToPoint);
1411 y0 = mLayouter->mCoordArrayY->lanePosition(iy0, j0? j0->
rect().
bottom() : 0);
1412 y1 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j1 ? j1->
rect().
top() : 0,
true)
1413 : mLayouter->mCoordArrayY->lanePosition(iy1,0);
1418 auto itEpc = mLayouter->mEndpointHash.find(wFromPoint);
1419 y0 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j0 ? j0->
rect().
bottom() : 0,
true)
1420 : mLayouter->mCoordArrayY->lanePosition(iy0,0);
1421 y1 = mLayouter->mCoordArrayY->lanePosition(iy1, j1? j1->
rect().
top() : 0);
1431 void DrawNetThread::drawJunction()
1433 for (
auto jt = mLayouter->mJunctionHash.
constBegin(); jt != mLayouter->mJunctionHash.
constEnd(); ++jt)
1435 auto epcIt = mLayouter->mEndpointHash.find(jt.key());
1436 int x = jt.key().x();
1437 int y = jt.key().y();
1438 bool isEndpoint = (y % 2 == 0);
1442 int li = jw.mIndex.laneIndex();
1443 if (jw.mIndex.isHorizontal())
1445 Q_ASSERT(epcIt != mLayouter->mEndpointHash.constEnd() || !isEndpoint);
1446 float x0 = mLayouter->mCoordArrayX->lanePosition(x,jw.mRange.first());
1447 float x1 = mLayouter->mCoordArrayX->lanePosition(x,jw.mRange.last());
1448 float yy = isEndpoint ? epcIt.value().lanePosition(li,
true) : mLayouter->mCoordArrayY->lanePosition(y,li);
1456 y0 = mLayouter->mCoordArrayY->lanePosition(y,jw.mRange.first());
1457 y1 = mLayouter->mCoordArrayY->lanePosition(y,jw.mRange.last());
1459 else if (epcIt != mLayouter->mEndpointHash.constEnd())
1461 y0 = epcIt.value().lanePosition(jw.mRange.first(),
true);
1462 y1 = epcIt.value().lanePosition(jw.mRange.last(),
true);
1466 y0 = mLayouter->mCoordY.
value(y).junctionEntry();
1467 y1 = mLayouter->mCoordY.
value(y).junctionExit();
1471 float xx = mLayouter->mCoordArrayX->lanePosition(x,li);
1476 for (
const QPoint& pnt : jt.value()->netById(mId).mKnots)
1478 float xp = mLayouter->mCoordArrayX->lanePosition(x,pnt.x());
1479 float yp = isEndpoint ? epcIt.value().lanePosition(pnt.y(),
true) : mLayouter->mCoordArrayY->lanePosition(y,pnt.y());
1485 void DrawNetThread::drawEndpoint()
1487 for (
auto it = mLayouter->mEndpointHash.constBegin(); it != mLayouter->mEndpointHash.constEnd(); ++it)
1489 const GraphLayouter::EndpointCoordinate& epc = it.value();
1491 QList<int> inputsById = epc.inputPinIndex(mId);
1492 QList<int> outputsById = epc.outputPinIndex(mId);
1496 const NetLayoutJunction* nlj = mLayouter->mJunctionHash.
value(it.key());
1497 int ix = it.key().x();
1498 float xjLeft = mLayouter->mCoordArrayX->lanePosition(ix,nlj?nlj->rect().left():0);
1499 float xjRight = mLayouter->mCoordArrayX->lanePosition(ix,nlj?nlj->rect().right():0);
1501 for (
int inpInx : inputsById)
1503 if (xjRight >= epc.xInput())
1506 auto ityOut = mLayouter->mGlobalOutputHash.
find(mId);
1507 if (ityOut == mLayouter->mGlobalOutputHash.
constEnd() ||
QPoint(mLayouter->mNodeBoundingBox.
right() + 1, 2 * ityOut.value()) != it.key())
1508 qDebug() <<
"cannot connect input pin" << mId << it.key().x() << it.key().y() / 2 << xjRight << epc.xInput();
1513 for (
int outInx : outputsById)
1515 if (epc.xOutput() >= xjLeft)
1516 qDebug() <<
"cannot connect output pin" << mId << it.key().x() << it.key().y() / 2 << xjLeft << epc.xOutput();
SelectionDetailsWidget * getSelectionDetailsWidget()
StandardGraphicsNet::Lines mLines
Logical container for modules, gates, and nets.
void layoutProgress(int percent) const
const QSet< u32 > & nets() const
QVector< qreal > yValues() const
qreal gridXposition(int ix) const
void setNodePosition(const Node &n, const QPoint &p)
void removeNodeFromMaps(const Node &n)
QVector< qreal > xValues() const
QMap< Node, QPoint > mNodeToPositionRollback
qreal defaultGridHeight() const
void setDumpJunctionEnabled(bool enabled)
void swapNodePositions(const Node &n1, const Node &n2)
QMap< QPoint, Node > mPositionToNodeMap
const QMap< QPoint, Node > positionToNodeMap() const
NetLayoutPoint positonForNode(const Node &nd) const
GraphLayouter(GraphContext *context, QObject *parent=nullptr)
void dumpNodePositions(const QPoint &search) const
const QMap< Node, QPoint > nodeToPositionMap() const
qreal maxNodeWidth() const
qreal gridYposition(int iy) const
bool dumpJunctionEnabled()
friend class DrawNetThread
qreal maxNodeHeight() const
Node nodeAtPosition(const QPoint &p) const
GridPlacement * gridPlacementFactory() const
GraphicsScene * scene() const
qreal defaultGridWidth() const
QPoint gridPointByItem(GraphicsNode *item) const
GraphContext * mParentContext
QMap< Node, QPoint > mNodeToPositionMap
void updatePlacement(const GridPlacement &plc)
Abstract base class for nodes (e.g. gates, modules)
Container for a GraphGraphicsView containing gates, nets, and modules.
void handleHighlight(const QVector< const ModuleItem * > &highlightItems)
void handleExternSelectionChanged(void *sender)
void addGraphItem(GraphicsItem *item)
void moveNetsToBackground()
NetLayoutJunction * mJunction
NetLayoutJunctionEntries mEntries
Module * get_module_by_id(u32 module_id) const
Net * get_net_by_id(u32 net_id) const
The NodeBox class represents a node placed at a grid position within a hal view.
int x() const
x getter for X-grid position
int y() const
y getter for Y-grid position
void addBox(const Node &nd, int px, int py)
addBox call NodeBox constructor and store pointer in vector
NodeBox * boxForPoint(const QPoint &p) const
boxForPoint find NodeBox by grid position
NodeBox * boxForGate(const Gate *g) const
boxForGate find NodeBox by Gate pointer.
NodeBox * boxForItem(GraphicsNode *item) const
boxForItem find NodeBox by graphics item
void clearBoxes()
clearBoxes delete all NodeBox'es and clear vector.
The Node class object represents a module or a gate.
bool isNull() const
isNull test for null-Node object typically returned from functions
ContentManager * gContentManager
CommentManager * gCommentManager
qint64 elapsed() const const
void addItem(QGraphicsItem *item)
QRectF itemsBoundingRect() const const
void removeItem(QGraphicsItem *item)
void setSceneRect(const QRectF &rect)
QHash::const_iterator constBegin() const const
QHash::const_iterator constEnd() const const
QHash::iterator find(const Key &key)
QHash::iterator insert(const Key &key, const T &value)
bool isEmpty() const const
const T value(const Key &key) const const
void append(const T &value)
const T & at(int i) const const
bool isEmpty() const const
const Key & key() const const
const T & value() const const
const Key & key() const const
QMap::const_iterator constBegin() const const
QMap::const_iterator constEnd() const const
bool contains(const Key &key) const const
QMap::iterator find(const Key &key)
QMap::iterator insert(const Key &key, const T &value)
bool isEmpty() const const
const Key key(const T &value, const Key &defaultKey) const const
const T value(const Key &key, const T &defaultValue) const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * sender() const const
void adjust(int dx1, int dy1, int dx2, int dy2)
QSet::const_iterator constBegin() const const
QSet::const_iterator constEnd() const const
bool contains(const T &value) const const
QSet::iterator insert(const T &value)
QList< T > toList() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromStdString(const std::string &str)
void setFieldAlignment(QTextStream::FieldAlignment mode)
void setFieldWidth(int width)
void append(const T &value)
bool isEmpty() const const
void appendHLine(const qreal mSmallX, const qreal mBigX, const qreal y)
void appendVLine(const qreal x, const qreal mSmallY, const qreal mBigY)