22 #include <QApplication>
23 #include <QElapsedTimer>
28 template<
typename T1,
typename T2>
29 static void storeMax(
QMap<T1, T2>& map, T1 key, T2 value)
32 if (map.
value(key) >= value)
38 const static qreal sLaneSpacing = 10;
39 const static qreal sHRoadPadding = 10;
40 const static qreal sVRoadPadding = 10;
41 const static qreal sMinimumVChannelWidth = 20;
42 const static qreal sMinimumHChannelHeight = 20;
45 :
QObject(parent), mScene(new
GraphicsScene(this)), mParentContext(context), mDone(false), mRollbackStatus(0), mDumpJunctions(false)
75 retval->
insert(it.key(),it.value());
95 xout <<
"Node positions " << search.
x() <<
" " << search.
y() <<
"\n";
100 xout << (it.key() == search ?
"*" :
" ") << it.key().x() << it.key().y() << (it.value().type() ==
Node::Module ?
"M" :
"G") << it.value().id() <<
"\n";
122 --positionOccupied[jt.value()];
123 ++positionOccupied[it.value()];
124 jt.
value() = it.value();
128 for (
auto rpit = positionOccupied.
begin(); rpit != positionOccupied.
end(); ++rpit)
129 if (rpit.value() < 0)
174 QPoint retval(INT_MIN, INT_MIN);
180 return QPoint(nbox->
x(), nbox->
y());
210 return mMaxNodeWidth;
215 return mMaxNodeHeight;
220 return mMaxNodeWidth + sMinimumVChannelWidth;
225 return mMaxNodeHeight + sMinimumHChannelHeight;
231 int inx = ix - mMinXIndex;
234 if (inx < mXValues.
size())
235 return mXValues[inx];
242 int inx = iy - mMinYIndex;
245 if (inx < mYValues.
size())
246 return mYValues[inx];
266 findMaxBoxDimensions();
268 findMaxChannelLanes();
270 calculateJunctionMinDistance();
272 calculateGateOffsets();
275 mCoordArrayX =
new SceneCoordinateArray(mCoordX);
276 mCoordArrayY =
new SceneCoordinateArray(mCoordY);
287 #ifdef GUI_DEBUG_GRID
292 qDebug() <<
"elapsed time (experimental new) layout [ms]" << timer.
elapsed();
314 mRollbackStatus = -1;
323 void GraphLayouter::clearComments()
330 mCommentBubbles.clear();
333 void GraphLayouter::clearLayoutData()
340 mMaxNodeWidthForX.
clear();
341 mMaxNodeHeightForY.
clear();
343 mNodeOffsetForX.
clear();
344 mNodeOffsetForY.
clear();
346 mMaxLeftIoPaddingForChannelX.
clear();
347 mMaxRightIoPaddingForChannelX.
clear();
349 mMinXIndex = INT_MAX;
350 mMinYIndex = INT_MAX;
352 mMaxXIndex = INT_MIN;
353 mMaxYIndex = INT_MIN;
363 mEndpointHash.clear();
365 mJunctionEntries.clear();
366 mSeparatedWidth.clear();
369 mJunctionMinDistanceY.
clear();
370 mWireEndpoint.
clear();
371 mGlobalInputHash.
clear();
372 mGlobalOutputHash.
clear();
373 mNodeBoundingBox =
QRect();
380 void GraphLayouter::createBoxes()
383 int xmin, xmax, ymin, ymax;
384 xmin = ymin = xmax = ymax = 0;
390 if (first || x + 1 > xmax)
392 if (first || y + 1 > ymax)
394 if (first || x < xmin)
396 if (first || y < ymin)
402 mNodeBoundingBox =
QRect(xmin, ymin, xmax - xmin, ymax - ymin);
405 bool GraphLayouter::verifyModulePort(Net*
n,
const Node& modNode,
bool isModInput)
415 if (std::unordered_set<Net*> nets = m->get_input_nets(); nets.find(
n) != nets.end())
422 if (std::unordered_set<Net*> nets = m->get_output_nets(); nets.find(
n) != nets.end())
431 void GraphLayouter::handleCommentAboutToDeleted(CommentEntry* entry)
440 void GraphLayouter::handleCommentAdded(CommentEntry* entry)
449 void GraphLayouter::getWireHash()
461 mWireEndpoint[
id] = EndpointList();
463 for (
const Endpoint* src :
n->get_sources())
466 const NodeBox* srcBox = mBoxes.
boxForGate(src->get_gate());
470 mViewInput.
insert(
n->get_id());
474 if (!verifyModulePort(
n, srcBox->getNode(),
false))
477 NetLayoutPoint srcPnt(srcBox->x() + 1, 2 * srcBox->y());
479 mWireEndpoint[
id].addSource(srcPnt);
482 for (
const Endpoint* dst :
n->get_destinations())
485 const NodeBox* dstBox = mBoxes.
boxForGate(dst->get_gate());
489 mViewOutput.
insert(
n->get_id());
493 if (!verifyModulePort(
n, dstBox->getNode(),
true))
496 NetLayoutPoint dstPnt(dstBox->x(), 2 * dstBox->y());
498 mWireEndpoint[
id].addDestination(dstPnt);
502 mWireEndpoint[
id].setNetType(EndpointList::ConstantLevel);
505 EndpointList::EndpointType nType = mWireEndpoint.
value(
id).netType();
506 if ((nType == EndpointList::SingleDestination && dstPoints.
size() > 1) || (nType == EndpointList::SourceAndDestination && mViewInput.
contains(
n->get_id())))
509 int ypos = mGlobalInputHash.
size();
510 NetLayoutPoint srcPnt(mNodeBoundingBox.
left(), 2 * ypos);
512 mWireEndpoint[
id].addSource(srcPnt);
513 mGlobalInputHash[
id] = ypos;
514 mWireEndpoint[
id].setNetType(EndpointList::HasGlobalEndpoint);
515 mWireEndpoint[
id].setInputArrow();
518 if ((nType == EndpointList::SingleSource && srcPoints.
size() > 1) || (nType == EndpointList::SourceAndDestination && mViewOutput.
contains(
n->get_id())))
521 int ypos = mGlobalOutputHash.
size();
522 NetLayoutPoint dstPnt(mNodeBoundingBox.
right() + 1, 2 * ypos);
524 mWireEndpoint[
id].addDestination(dstPnt);
525 mGlobalOutputHash[
id] = ypos;
526 mWireEndpoint[
id].setNetType(EndpointList::HasGlobalEndpoint);
527 mWireEndpoint[
id].setOutputArrow();
530 const EndpointList& epl = mWireEndpoint.
value(
id);
531 switch (epl.netType())
533 case EndpointList::SingleSource:
534 case EndpointList::SingleDestination:
535 case EndpointList::ConstantLevel: {
537 for (
const NetLayoutPoint& pnt : epl)
539 bool isInput = epl.isInput(ipnt++);
540 SeparatedGraphicsNet* net_item = epl.netType() == EndpointList::ConstantLevel
542 :
static_cast<SeparatedGraphicsNet*
>(
new ArrowSeparatedNet(
n));
544 mSeparatedWidth[pnt].requireInputSpace(net_item->inputWidth() + sLaneSpacing);
549 mSeparatedWidth[pnt].requireOutputSpace(nb->item()->width() + net_item->outputWidth() + sLaneSpacing);
555 case EndpointList::SourceAndDestination:
556 case EndpointList::HasGlobalEndpoint:
558 NetLayoutConnectionFactory nlcf(srcPoints.
toList(), dstPoints.
toList());
560 mConnectionMetric.
insert(NetLayoutMetric(
id, nlcf.connection), nlcf.connection);
569 for (
auto it = mConnectionMetric.
constBegin(); it != mConnectionMetric.
constEnd(); ++it)
571 u32 id = it.
key().getId();
572 const NetLayoutConnection* nlc = it.value();
573 for (
const NetLayoutWire& w : *nlc)
575 mWireHash[w].append(
id);
580 for (
auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it)
582 for (
int iend = 0; iend < 2; iend++)
587 mJunctionEntries[pnt].mEntries[idirBase + iend] = it.value();
592 for (
const NodeBox* nbox : mBoxes)
594 NetLayoutPoint inPnt(nbox->x(), nbox->y() * 2);
595 QList<u32> inpNets = nbox->item()->inputNets();
597 mEndpointHash[inPnt].setInputPins(nbox->item()->inputNets(), nbox->item()->yTopPinDistance(), nbox->item()->yEndpointDistance());
598 NetLayoutPoint outPnt(nbox->x() + 1, nbox->y() * 2);
600 mEndpointHash[outPnt].setOutputPins(nbox->item()->outputNets(), nbox->item()->yTopPinDistance(), nbox->item()->yEndpointDistance());
603 for (
auto itGlInp = mGlobalInputHash.
constBegin(); itGlInp != mGlobalInputHash.
constEnd(); ++itGlInp)
606 netIds.
append(itGlInp.key());
607 NetLayoutPoint pnt(mNodeBoundingBox.
left(), 2 * itGlInp.value());
609 if (!mEndpointHash.contains(pnt))
610 mEndpointHash[pnt].setOutputPins(netIds, 0, 0);
613 for (
auto itGlOut = mGlobalOutputHash.
constBegin(); itGlOut != mGlobalOutputHash.
constEnd(); ++itGlOut)
616 netIds.
append(itGlOut.key());
617 NetLayoutPoint pnt(mNodeBoundingBox.
right() + 1, 2 * itGlOut.value());
619 if (!mEndpointHash.contains(pnt))
620 mEndpointHash[pnt].setInputPins(netIds, 0, 0);
623 auto it = mJunctionEntries.constBegin();
624 while (it != mJunctionEntries.constEnd() || !mJunctionThreads.isEmpty())
628 if (!it.value().isTrivial())
631 it.value().dumpToFile(it.key());
632 JunctionThread* jt =
new JunctionThread(it.key(), it.value());
634 mJunctionThreads.append(jt);
639 qApp->processEvents();
643 void GraphLayouter::findMaxBoxDimensions()
645 for (
const NodeBox* box : mBoxes)
647 if (box->x() < mMinXIndex)
648 mMinXIndex = box->x();
649 else if (box->x() > mMaxXIndex)
650 mMaxXIndex = box->x();
652 if (box->y() < mMinYIndex)
653 mMinYIndex = box->y();
654 else if (box->y() > mMaxYIndex)
655 mMaxYIndex = box->y();
657 if (mMaxNodeWidth < box->item()->width())
658 mMaxNodeWidth = box->item()->width();
660 if (mMaxNodeHeight < box->item()->height())
661 mMaxNodeHeight = box->item()->height();
663 storeMax(mMaxNodeWidthForX, box->x(), box->item()->width());
664 storeMax(mMaxNodeHeightForY, box->y(), box->item()->height());
666 storeMax(mMaxRightIoPaddingForChannelX, box->x(), box->inputPadding());
667 storeMax(mMaxLeftIoPaddingForChannelX, box->x() + 1, box->outputPadding());
671 void GraphLayouter::findMaxChannelLanes()
674 for (
auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it)
677 unsigned int nw = it.value().size();
678 if (it.key().isHorizontal())
679 mCoordY[pnt.y()].testMinMax(nw);
681 mCoordX[pnt.x()].testMinMax(nw);
687 const NetLayoutPoint& pnt = it.
key();
688 const QRect& rect = it.value()->rect();
689 mCoordX[pnt.x()].testMinMax(rect.
left());
690 mCoordX[pnt.x()].testMinMax(rect.
right());
691 mCoordY[pnt.y()].testMinMax(rect.
top());
692 mCoordY[pnt.y()].testMinMax(rect.
bottom());
697 mCoordX[mNodeBoundingBox.
left()].testMinMax(0);
699 mCoordY[mNodeBoundingBox.
top()].testMinMax(0);
704 auto itx0 = mCoordX.
begin();
705 for (
auto itx1 = itx0 + 1; itx1 != mCoordX.
end(); ++itx1)
707 for (
int x = itx0.key() + 1; x < itx1.key(); x++)
708 mCoordX[x].testMinMax(0);
714 auto ity0 = mCoordY.
begin();
715 for (
auto ity1 = ity0 + 1; ity1 != mCoordY.
end(); ++ity1)
717 for (
int y = ity0.key() + 1; y < ity1.key(); y++)
718 mCoordY[y].testMinMax(0);
724 void GraphLayouter::calculateJunctionMinDistance()
726 for (
auto itJun = mJunctionHash.
constBegin(); itJun != mJunctionHash.
constEnd(); ++itJun)
728 const NetLayoutPoint& pnt0 = itJun.
key();
729 NetLayoutPoint pnt1 = pnt0 +
QPoint(0, 1);
730 const NetLayoutJunction* j1 = mJunctionHash.
value(pnt1);
733 const NetLayoutJunction* j0 = itJun.value();
734 auto itEdp = mEndpointHash.find(pnt1.isEndpoint() ? pnt1 : pnt0);
735 if (itEdp == mEndpointHash.constEnd())
737 float minDistance = 0;
739 if (pnt1.isEndpoint())
742 minDistance = (j0->rect().bottom() + 1) * sLaneSpacing - itEdp.value().lanePosition(j1->rect().top(),
false);
747 minDistance = itEdp.value().lanePosition(j0->rect().bottom(),
false) + (1 - j1->rect().top()) * sLaneSpacing;
749 if (minDistance > mJunctionMinDistanceY[iy])
750 mJunctionMinDistanceY[iy] = minDistance;
754 void GraphLayouter::calculateGateOffsets()
758 for (
auto itSep = mSeparatedWidth.constBegin(); itSep != mSeparatedWidth.constEnd(); itSep++)
760 NetLayoutJunction* jx = mJunctionHash.
value(itSep.key());
763 int ix = itSep.key().x();
764 float xinp = jx->rect().right() * sLaneSpacing + itSep.value().mInputSpace;
765 float xout = itSep.value().mOutputSpace - jx->rect().left() * sLaneSpacing;
766 if (xinp > xInputPadding[ix])
767 xInputPadding[ix] = xinp;
768 if (xout > xOutputPadding[ix])
769 xOutputPadding[ix] = xout;
772 int ix0 = mNodeBoundingBox.
x();
774 float x0 = mCoordX[ix0].preLanes() * sLaneSpacing + sHRoadPadding;
775 if (!mGlobalInputHash.
isEmpty())
777 mCoordX[ix0].setOffset(x0);
778 mCoordX[ix0].setPadding(xInputPadding[ix0]);
782 auto itxLast = mCoordX.
begin();
783 for (
auto itNext = itxLast + 1; itNext != mCoordX.
end(); ++itNext)
786 int ix1 = itNext.key();
790 for (
int ix = ix0; ix < ix1; ix++)
792 auto xn = mMaxNodeWidthForX.
find(ix);
793 if (xn != mMaxNodeWidthForX.
end())
796 itNext->setOffsetX(itxLast.value(), xsum + 2 * sHRoadPadding, xOutputPadding[ix1], xInputPadding[ix1]);
797 mXValues.
append(itNext.value().xBoxOffset());
801 int iy0 = mNodeBoundingBox.
y() * 2;
802 float y0 = mCoordY[iy0].preLanes() * sLaneSpacing + sVRoadPadding;
803 mCoordY[iy0].setOffset(y0);
804 auto ityLast = mCoordY.
begin();
805 for (
auto itNext = ityLast + 1; itNext != mCoordY.
end(); ++itNext)
808 int iy1 = itNext.key();
813 itNext->setOffsetYje(ityLast.value(), mJunctionMinDistanceY.
value(iy1));
818 float ydelta = sVRoadPadding;
819 auto yn = mMaxNodeHeightForY.
find(iy0 / 2);
820 if (yn != mMaxNodeHeightForY.
constEnd())
821 ydelta += yn.
value();
822 itNext->setOffsetYej(ityLast.value(), ydelta, mJunctionMinDistanceY.
value(iy1));
827 iy0 = mNodeBoundingBox.
y() * 2;
828 auto ity = mCoordY.
find(iy0);
829 while(ity != mCoordY.
end())
831 mYValues.
append(ity.value().lanePosition(0));
833 ity = mCoordY.
find(iy0);
837 void GraphLayouter::placeGates()
839 for (
const NodeBox* box : mBoxes)
841 box->item()->setPos(mCoordX[box->x()].xBoxOffset(), mCoordY[box->y() * 2].lanePosition(0));
844 NetLayoutPoint outPnt(box->x() + 1, box->y() * 2);
845 QPointF outPos = box->item()->endpointPositionByIndex(0,
false);
846 mEndpointHash[outPnt].setOutputPosition(outPos);
848 NetLayoutPoint inPnt(box->x(), box->y() * 2);
849 QPointF inPos = box->item()->endpointPositionByIndex(0,
true);
850 mEndpointHash[inPnt].setInputPosition(inPos);
854 for (
auto itEp = mEndpointHash.begin(); itEp != mEndpointHash.end(); ++itEp)
856 if (itEp.value().lanePosition(0,
true) <= 0)
858 float px = mCoordX[itEp.key().x()].lanePosition(-1);
859 float py = mCoordY[itEp.key().y()].lanePosition(0);
860 itEp->setOutputPosition(
QPointF(px, py));
865 void GraphLayouter::drawComments()
867 for (NodeBox* box : mBoxes)
871 CommentSpeechBubble* csb =
new CommentSpeechBubble(
QString(
"%1 [%2]").arg(ce->getHeader()).
arg(ce->getCreationTime().toString(
"dd.MM.yy")),
873 QPointF pos = box->item()->pos() +
QPointF(box->item()->width(),0);
875 mCommentBubbles.append(csb);
880 void GraphLayouter::drawNets()
884 for (
auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it)
887 for (
u32 id : it.value())
888 mLaneMap[
id].insert(it.key(), ilane++);
892 int percentCount = netCount / 93;
900 enum LoopState { LoopInit, CanStartThread, WaitForSlot, WaitForLastThread, LoopDone } loopState = LoopInit;
901 while (loopState != LoopDone)
903 if (mNetIterator != mNetsToDraw.
constEnd())
906 loopState = CanStartThread;
908 loopState = WaitForSlot;
912 if (mDrawNetThreads.isEmpty())
913 loopState = LoopDone;
915 loopState = WaitForLastThread;
918 if (loopState == LoopDone)
921 if (loopState == WaitForLastThread || loopState == WaitForSlot)
923 qApp->processEvents();
927 Q_ASSERT(loopState == CanStartThread);
928 u32 id = *(mNetIterator++);
934 const EndpointList& epl = mWireEndpoint.
value(
id);
935 bool regularNet =
false;
937 switch (epl.netType())
939 case EndpointList::NoEndpoint:
942 case EndpointList::SingleSource:
943 case EndpointList::SingleDestination:
944 case EndpointList::ConstantLevel:
946 drawNetsIsolated(
id,
n, epl);
960 if (doneCount % percentCount == 0)
968 mDrawNetThreads.append(dnt);
973 void GraphLayouter::handleJunctionThreadFinished()
975 JunctionThread* jt =
static_cast<JunctionThread*
>(
sender());
976 mJunctionHash.
insert(jt->mNetLayoutPoint,jt->mJunction);
977 mJunctionThreads.removeAll(jt);
981 void GraphLayouter::handleDrawNetThreadFinished()
985 const EndpointList& epl = mWireEndpoint.
value(dnt->id());
987 GraphicsNet* graphicsNet =
nullptr;
988 switch (epl.netType())
990 case EndpointList::HasGlobalEndpoint:
991 if (epl.hasInputArrow())
993 StandardArrowNet* san =
new StandardArrowNet(
n, dnt->mLines, dnt->mKnots);
995 int yGridPos = mGlobalInputHash.
value(dnt->id(), -1);
996 Q_ASSERT(yGridPos >= 0);
997 QPoint pnt(mNodeBoundingBox.
left(), yGridPos * 2);
998 const EndpointCoordinate& epc = mEndpointHash.value(pnt);
999 const NetLayoutJunction* nlj = mJunctionHash.
value(pnt);
1000 san->setInputPosition(
QPointF(mCoordArrayX->lanePosition(mNodeBoundingBox.
left(),nlj?nlj->rect().left():0), epc.lanePosition(0,
true)));
1002 if (epl.hasOutputArrow())
1005 StandardArrowNet* san =
new StandardArrowNet(
n, dnt->mLines, dnt->mKnots);
1007 int yGridPos = mGlobalOutputHash.
value(dnt->id(), -1);
1008 Q_ASSERT(yGridPos >= 0);
1009 QPoint pnt(mNodeBoundingBox.
right() + 1, yGridPos * 2);
1010 const EndpointCoordinate& epc = mEndpointHash.value(pnt);
1011 const NetLayoutJunction* nlj = mJunctionHash.
value(pnt);
1012 san->setOutputPosition(
QPointF(mCoordArrayX->lanePosition(pnt.x(),nlj?nlj->rect().right():0), epc.lanePosition(0,
true)));
1015 case EndpointList::SourceAndDestination:
1016 if (dnt->mLines.nLines() > 0)
1017 graphicsNet =
new StandardGraphicsNet(
n, dnt->mLines, dnt->mKnots);
1027 mDrawNetThreads.removeAll(dnt);
1031 void GraphLayouter::drawNetsIsolated(
u32 id, Net*
n,
const EndpointList& epl)
1033 SeparatedGraphicsNet* net_item = epl.netType() == EndpointList::ConstantLevel ?
static_cast<SeparatedGraphicsNet*
>(
new LabeledSeparatedNet(
n,
QString::fromStdString(
n->get_name())))
1034 :
static_cast<SeparatedGraphicsNet*
>(
new ArrowSeparatedNet(
n));
1037 for (
const NetLayoutPoint& pnt : epl)
1039 bool isInput = epl.isInput(ipnt++);
1040 auto itPnt = mEndpointHash.find(pnt);
1041 Q_ASSERT(itPnt != mEndpointHash.constEnd());
1045 const NodeBox* nbox = mBoxes.boxForPoint(pnt.gridPoint());
1047 QList<u32> inpList = nbox->item()->inputNets();
1048 for (
int jnx = 0; jnx < inpList.
size(); jnx++)
1050 u32 inpNetId = inpList.
at(jnx);
1053 QPointF inpPnt(itPnt.value().xInput(), itPnt.value().lanePosition(jnx,
true));
1054 net_item->addInput(inpPnt);
1059 for (
int inx : itPnt.value().outputPinIndex(
id))
1061 QPointF outPnt(itPnt.value().xOutput(), itPnt.value().lanePosition(inx,
true));
1062 net_item->addOutput(outPnt);
1066 net_item->finalize();
1070 void GraphLayouter::updateSceneRect()
1076 rect.
adjust(-200, -200, 200, 200);
1080 bool GraphLayouter::boxExists(
const int x,
const int y)
const
1082 return mBoxes.boxForPoint(
QPoint(x, y)) !=
nullptr;
1085 bool GraphLayouter::hRoadJumpPossible(
const int x,
const int y1,
const int y2)
const
1091 int difference = y1 - y2;
1096 difference = y2 - y1;
1101 if (boxExists(x, bottom_y - difference))
1110 bool GraphLayouter::hRoadJumpPossible(
const GraphLayouter::Road*
const r1,
const GraphLayouter::Road*
const r2)
const
1114 assert(r1->x != r2->x);
1116 return hRoadJumpPossible(r1->x, r1->y, r2->y);
1119 bool GraphLayouter::vRoadJumpPossible(
const int x1,
const int x2,
const int y)
const
1125 int difference = x1 - x2;
1130 difference = x2 - x1;
1135 if (boxExists(right_x - difference, y))
1144 bool GraphLayouter::vRoadJumpPossible(
const GraphLayouter::Road*
const r1,
const GraphLayouter::Road*
const r2)
const
1148 assert(r1->y != r2->y);
1150 return vRoadJumpPossible(r1->x, r2->x, r1->y);
1153 qreal GraphLayouter::hRoadHeight(
const unsigned int mLanes)
const
1156 qreal height = sHRoadPadding * 2;
1159 height += (mLanes - 1) * sLaneSpacing;
1164 qreal GraphLayouter::vRoadWidth(
const unsigned int mLanes)
const
1167 qreal width = sVRoadPadding * 2;
1170 width += (mLanes - 1) * sLaneSpacing;
1175 void GraphLayouter::SceneCoordinate::testMinMax(
int ilane)
1177 if (ilane < minLane)
1179 if (ilane + 1 > maxLane)
1180 maxLane = ilane + 1;
1183 void GraphLayouter::SceneCoordinate::setOffsetX(
const SceneCoordinate& previous,
float maximumBlock,
float sepOut,
float sepInp)
1185 float delta = maximumBlock;
1188 mOffset = previous.xBoxOffset() + (1 - minLane) * sLaneSpacing + delta;
1189 float xDefaultBoxPadding = maxLane * sLaneSpacing;
1190 if (xDefaultBoxPadding < sepInp)
1191 mPadding = sepInp - xDefaultBoxPadding;
1194 void GraphLayouter::SceneCoordinate::setOffsetYje(
const SceneCoordinate& previous,
float minimumJunction)
1196 float delta = (previous.maxLane) * sLaneSpacing + sVRoadPadding;
1197 if (delta < minimumJunction)
1198 delta = minimumJunction;
1199 mOffset = previous.mOffset + delta;
1202 void GraphLayouter::SceneCoordinate::setOffsetYej(
const SceneCoordinate& previous,
float maximumBlock,
float minimumJunction)
1204 float delta = (-minLane - 1) * sLaneSpacing + maximumBlock + sVRoadPadding;
1205 if (delta < minimumJunction)
1206 delta = minimumJunction;
1207 mOffset = previous.mOffset + delta;
1210 float GraphLayouter::SceneCoordinate::lanePosition(
int ilane)
const
1212 return mOffset + ilane * sLaneSpacing;
1215 float GraphLayouter::SceneCoordinate::xBoxOffset()
const
1217 return junctionExit() + sHRoadPadding + mPadding;
1221 : mArray(nullptr), mFirstIndex(0)
1225 mArray =
new float[inputMap.
size()];
1227 mFirstIndex = it.
key();
1228 for (
int i = 0; it != inputMap.
constEnd(); ++it)
1230 mArray[i++] = it.value().lanePosition(0);
1235 GraphLayouter::SceneCoordinateArray::~SceneCoordinateArray()
1237 if (mArray)
delete [] mArray;
1240 float GraphLayouter::SceneCoordinateArray::lanePosition(
int igrid,
int ilane)
const
1242 return mArray[igrid-mFirstIndex] + ilane * sLaneSpacing;
1245 float GraphLayouter::EndpointCoordinate::lanePosition(
int ilane,
bool absolute)
const
1247 float y0 = absolute ? mYoffset : mTopPin;
1249 return y0 + ilane * sLaneSpacing;
1250 int n = numberPins() - 1;
1252 return y0 + ilane * mPinDistance;
1253 return y0 +
n * mPinDistance + (ilane -
n) * sLaneSpacing;
1256 GraphLayouter::EndpointCoordinate::EndpointCoordinate() : mYoffset(0), mXoutput(0), mXinput(0), mPinDistance(0), mTopPin(0), mNumberPins(0)
1261 int GraphLayouter::EndpointCoordinate::numberPins()
const
1266 void GraphLayouter::EndpointCoordinate::setInputPosition(
QPointF p0pos)
1268 mXinput = p0pos.
x();
1269 mYoffset = p0pos.
y();
1272 void GraphLayouter::EndpointCoordinate::setOutputPosition(
QPointF p0pos)
1274 mXoutput = p0pos.
x();
1275 if (mXinput < mXoutput)
1277 mYoffset = p0pos.
y();
1280 QList<int> GraphLayouter::EndpointCoordinate::inputPinIndex(
u32 id)
const
1282 return mInputHash.values(
id);
1285 QList<int> GraphLayouter::EndpointCoordinate::outputPinIndex(
u32 id)
const
1287 return mOutputHash.values(
id);
1290 void GraphLayouter::EndpointCoordinate::setInputPins(
const QList<u32>& pinList,
float p0dist,
float pdist)
1292 int n = pinList.
size();
1293 if (
n > mNumberPins)
1295 for (
int i = 0; i <
n; i++)
1297 u32 id = pinList.
at(i);
1299 mInputHash.insert(
id, i);
1301 if (p0dist > mTopPin)
1303 mPinDistance = pdist;
1306 void GraphLayouter::EndpointCoordinate::setOutputPins(
const QList<u32>& pinList,
float p0dist,
float pdist)
1308 int n = pinList.
size();
1309 if (
n > mNumberPins)
1311 for (
int i = 0; i <
n; i++)
1313 u32 id = pinList.
at(i);
1315 mOutputHash.insert(
id, i);
1317 if (p0dist > mTopPin)
1319 mPinDistance = pdist;
1322 void GraphLayouter::EndpointList::addSource(
const NetLayoutPoint& pnt)
1324 mNetType =
static_cast<EndpointType
>(mNetType | SingleSource);
1325 int existingIndex = indexOf(pnt);
1326 if (existingIndex >= 0 && !mPointIsInput.at(existingIndex))
1329 mPointIsInput.append(
false);
1332 void GraphLayouter::EndpointList::addDestination(
const NetLayoutPoint& pnt)
1334 mNetType =
static_cast<EndpointType
>(mNetType | SingleDestination);
1335 int existingIndex = indexOf(pnt);
1336 if (existingIndex >= 0 && mPointIsInput.at(existingIndex))
1339 mPointIsInput.append(
true);
1342 void GraphLayouter::SeparatedNetWidth::requireInputSpace(
float spc)
1344 if (spc > mInputSpace)
1348 void GraphLayouter::SeparatedNetWidth::requireOutputSpace(
float spc)
1350 if (spc > mOutputSpace)
1354 bool GraphLayouter::isConstNet(
const Net*
n)
1356 for (Endpoint* src :
n->get_sources())
1358 if (src->get_gate()->is_gnd_gate() || src->get_gate()->is_vcc_gate())
1366 return mDumpJunctions;
1371 mDumpJunctions = enabled;
1392 int ilane = it.value();
1393 int ix0 = wFromPoint.
x();
1394 int iy0 = wFromPoint.
y();
1395 int ix1 = wToPoint.
x();
1396 int iy1 = wToPoint.
y();
1398 if (it.key().isHorizontal())
1400 float x0 = mLayouter->mCoordArrayX->lanePosition(ix0,j0? j0->
rect().
right() : 0);
1401 float x1 = mLayouter->mCoordArrayX->lanePosition(ix1,j1? j1->
rect().
left() : 0);
1402 float yy = mLayouter->mCoordArrayY->lanePosition(iy0,ilane);
1408 float xx = mLayouter->mCoordArrayX->lanePosition(ix0,ilane);
1412 auto itEpc = mLayouter->mEndpointHash.find(wToPoint);
1413 y0 = mLayouter->mCoordArrayY->lanePosition(iy0, j0? j0->
rect().
bottom() : 0);
1414 y1 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j1 ? j1->
rect().
top() : 0,
true)
1415 : mLayouter->mCoordArrayY->lanePosition(iy1,0);
1420 auto itEpc = mLayouter->mEndpointHash.find(wFromPoint);
1421 y0 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j0 ? j0->
rect().
bottom() : 0,
true)
1422 : mLayouter->mCoordArrayY->lanePosition(iy0,0);
1423 y1 = mLayouter->mCoordArrayY->lanePosition(iy1, j1? j1->
rect().
top() : 0);
1433 void DrawNetThread::drawJunction()
1435 for (
auto jt = mLayouter->mJunctionHash.
constBegin(); jt != mLayouter->mJunctionHash.
constEnd(); ++jt)
1437 auto epcIt = mLayouter->mEndpointHash.find(jt.key());
1438 int x = jt.key().x();
1439 int y = jt.key().y();
1440 bool isEndpoint = (y % 2 == 0);
1444 int li = jw.mIndex.laneIndex();
1445 if (jw.mIndex.isHorizontal())
1447 Q_ASSERT(epcIt != mLayouter->mEndpointHash.constEnd() || !isEndpoint);
1448 float x0 = mLayouter->mCoordArrayX->lanePosition(x,jw.mRange.first());
1449 float x1 = mLayouter->mCoordArrayX->lanePosition(x,jw.mRange.last());
1450 float yy = isEndpoint ? epcIt.value().lanePosition(li,
true) : mLayouter->mCoordArrayY->lanePosition(y,li);
1458 y0 = mLayouter->mCoordArrayY->lanePosition(y,jw.mRange.first());
1459 y1 = mLayouter->mCoordArrayY->lanePosition(y,jw.mRange.last());
1461 else if (epcIt != mLayouter->mEndpointHash.constEnd())
1463 y0 = epcIt.value().lanePosition(jw.mRange.first(),
true);
1464 y1 = epcIt.value().lanePosition(jw.mRange.last(),
true);
1468 y0 = mLayouter->mCoordY.
value(y).junctionEntry();
1469 y1 = mLayouter->mCoordY.
value(y).junctionExit();
1473 float xx = mLayouter->mCoordArrayX->lanePosition(x,li);
1478 for (
const QPoint& pnt : jt.value()->netById(mId).mKnots)
1480 float xp = mLayouter->mCoordArrayX->lanePosition(x,pnt.x());
1481 float yp = isEndpoint ? epcIt.value().lanePosition(pnt.y(),
true) : mLayouter->mCoordArrayY->lanePosition(y,pnt.y());
1487 void DrawNetThread::drawEndpoint()
1489 for (
auto it = mLayouter->mEndpointHash.constBegin(); it != mLayouter->mEndpointHash.constEnd(); ++it)
1491 const GraphLayouter::EndpointCoordinate& epc = it.value();
1493 QList<int> inputsById = epc.inputPinIndex(mId);
1494 QList<int> outputsById = epc.outputPinIndex(mId);
1498 const NetLayoutJunction* nlj = mLayouter->mJunctionHash.
value(it.key());
1499 int ix = it.key().x();
1500 float xjLeft = mLayouter->mCoordArrayX->lanePosition(ix,nlj?nlj->rect().left():0);
1501 float xjRight = mLayouter->mCoordArrayX->lanePosition(ix,nlj?nlj->rect().right():0);
1503 for (
int inpInx : inputsById)
1505 if (xjRight >= epc.xInput())
1508 auto ityOut = mLayouter->mGlobalOutputHash.
find(mId);
1509 if (ityOut == mLayouter->mGlobalOutputHash.
constEnd() ||
QPoint(mLayouter->mNodeBoundingBox.
right() + 1, 2 * ityOut.value()) != it.key())
1510 qDebug() <<
"cannot connect input pin" << mId << it.key().x() << it.key().y() / 2 << xjRight << epc.xInput();
1515 for (
int outInx : outputsById)
1517 if (epc.xOutput() >= xjLeft)
1518 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)