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";
151 QPoint retval(INT_MIN, INT_MIN);
157 return QPoint(nbox->
x(), nbox->
y());
187 return mMaxNodeWidth;
192 return mMaxNodeHeight;
197 return mMaxNodeWidth + sMinimumVChannelWidth;
202 return mMaxNodeHeight + sMinimumHChannelHeight;
208 int inx = ix - mMinXIndex;
211 if (inx < mXValues.
size())
212 return mXValues[inx];
219 int inx = iy - mMinYIndex;
222 if (inx < mYValues.
size())
223 return mYValues[inx];
243 findMaxBoxDimensions();
245 findMaxChannelLanes();
247 calculateJunctionMinDistance();
249 calculateGateOffsets();
252 mCoordArrayX =
new SceneCoordinateArray(mCoordX);
253 mCoordArrayY =
new SceneCoordinateArray(mCoordY);
264 #ifdef GUI_DEBUG_GRID
269 qDebug() <<
"elapsed time (experimental new) layout [ms]" << timer.
elapsed();
291 mRollbackStatus = -1;
300 void GraphLayouter::clearComments()
307 mCommentBubbles.clear();
310 void GraphLayouter::clearLayoutData()
317 mMaxNodeWidthForX.
clear();
318 mMaxNodeHeightForY.
clear();
320 mNodeOffsetForX.
clear();
321 mNodeOffsetForY.
clear();
323 mMaxLeftIoPaddingForChannelX.
clear();
324 mMaxRightIoPaddingForChannelX.
clear();
326 mMinXIndex = INT_MAX;
327 mMinYIndex = INT_MAX;
329 mMaxXIndex = INT_MIN;
330 mMaxYIndex = INT_MIN;
340 mEndpointHash.clear();
342 mJunctionEntries.clear();
343 mSeparatedWidth.clear();
346 mJunctionMinDistanceY.
clear();
347 mWireEndpoint.
clear();
348 mGlobalInputHash.
clear();
349 mGlobalOutputHash.
clear();
350 mNodeBoundingBox =
QRect();
357 void GraphLayouter::createBoxes()
360 int xmin, xmax, ymin, ymax;
361 xmin = ymin = xmax = ymax = 0;
367 if (first || x + 1 > xmax)
369 if (first || y + 1 > ymax)
371 if (first || x < xmin)
373 if (first || y < ymin)
379 mNodeBoundingBox =
QRect(xmin, ymin, xmax - xmin, ymax - ymin);
382 bool GraphLayouter::verifyModulePort(Net*
n,
const Node& modNode,
bool isModInput)
392 if (std::unordered_set<Net*> nets = m->get_input_nets(); nets.find(
n) != nets.end())
399 if (std::unordered_set<Net*> nets = m->get_output_nets(); nets.find(
n) != nets.end())
408 void GraphLayouter::handleCommentAboutToDeleted(CommentEntry* entry)
417 void GraphLayouter::handleCommentAdded(CommentEntry* entry)
426 void GraphLayouter::getWireHash()
438 mWireEndpoint[
id] = EndpointList();
440 for (
const Endpoint* src :
n->get_sources())
443 const NodeBox* srcBox = mBoxes.
boxForGate(src->get_gate());
447 mViewInput.
insert(
n->get_id());
451 if (!verifyModulePort(
n, srcBox->getNode(),
false))
454 NetLayoutPoint srcPnt(srcBox->x() + 1, 2 * srcBox->y());
456 mWireEndpoint[
id].addSource(srcPnt);
459 for (
const Endpoint* dst :
n->get_destinations())
462 const NodeBox* dstBox = mBoxes.
boxForGate(dst->get_gate());
466 mViewOutput.
insert(
n->get_id());
470 if (!verifyModulePort(
n, dstBox->getNode(),
true))
473 NetLayoutPoint dstPnt(dstBox->x(), 2 * dstBox->y());
475 mWireEndpoint[
id].addDestination(dstPnt);
479 mWireEndpoint[
id].setNetType(EndpointList::ConstantLevel);
482 EndpointList::EndpointType nType = mWireEndpoint.
value(
id).netType();
483 if ((nType == EndpointList::SingleDestination && dstPoints.
size() > 1) || (nType == EndpointList::SourceAndDestination && mViewInput.
contains(
n->get_id())))
486 int ypos = mGlobalInputHash.
size();
487 NetLayoutPoint srcPnt(mNodeBoundingBox.
left(), 2 * ypos);
489 mWireEndpoint[
id].addSource(srcPnt);
490 mGlobalInputHash[
id] = ypos;
491 mWireEndpoint[
id].setNetType(EndpointList::HasGlobalEndpoint);
492 mWireEndpoint[
id].setInputArrow();
495 if ((nType == EndpointList::SingleSource && srcPoints.
size() > 1) || (nType == EndpointList::SourceAndDestination && mViewOutput.
contains(
n->get_id())))
498 int ypos = mGlobalOutputHash.
size();
499 NetLayoutPoint dstPnt(mNodeBoundingBox.
right() + 1, 2 * ypos);
501 mWireEndpoint[
id].addDestination(dstPnt);
502 mGlobalOutputHash[
id] = ypos;
503 mWireEndpoint[
id].setNetType(EndpointList::HasGlobalEndpoint);
504 mWireEndpoint[
id].setOutputArrow();
507 const EndpointList& epl = mWireEndpoint.
value(
id);
508 switch (epl.netType())
510 case EndpointList::SingleSource:
511 case EndpointList::SingleDestination:
512 case EndpointList::ConstantLevel: {
514 for (
const NetLayoutPoint& pnt : epl)
516 bool isInput = epl.isInput(ipnt++);
517 SeparatedGraphicsNet* net_item = epl.netType() == EndpointList::ConstantLevel
519 :
static_cast<SeparatedGraphicsNet*
>(
new ArrowSeparatedNet(
n));
521 mSeparatedWidth[pnt].requireInputSpace(net_item->inputWidth() + sLaneSpacing);
526 mSeparatedWidth[pnt].requireOutputSpace(nb->item()->width() + net_item->outputWidth() + sLaneSpacing);
532 case EndpointList::SourceAndDestination:
533 case EndpointList::HasGlobalEndpoint:
535 NetLayoutConnectionFactory nlcf(srcPoints.
toList(), dstPoints.
toList());
537 mConnectionMetric.
insert(NetLayoutMetric(
id, nlcf.connection), nlcf.connection);
546 for (
auto it = mConnectionMetric.
constBegin(); it != mConnectionMetric.
constEnd(); ++it)
548 u32 id = it.
key().getId();
549 const NetLayoutConnection* nlc = it.value();
550 for (
const NetLayoutWire& w : *nlc)
552 mWireHash[w].append(
id);
557 for (
auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it)
559 for (
int iend = 0; iend < 2; iend++)
564 mJunctionEntries[pnt].mEntries[idirBase + iend] = it.value();
569 for (
const NodeBox* nbox : mBoxes)
571 NetLayoutPoint inPnt(nbox->x(), nbox->y() * 2);
572 QList<u32> inpNets = nbox->item()->inputNets();
574 mEndpointHash[inPnt].setInputPins(nbox->item()->inputNets(), nbox->item()->yTopPinDistance(), nbox->item()->yEndpointDistance());
575 NetLayoutPoint outPnt(nbox->x() + 1, nbox->y() * 2);
577 mEndpointHash[outPnt].setOutputPins(nbox->item()->outputNets(), nbox->item()->yTopPinDistance(), nbox->item()->yEndpointDistance());
580 for (
auto itGlInp = mGlobalInputHash.
constBegin(); itGlInp != mGlobalInputHash.
constEnd(); ++itGlInp)
583 netIds.
append(itGlInp.key());
584 NetLayoutPoint pnt(mNodeBoundingBox.
left(), 2 * itGlInp.value());
586 if (!mEndpointHash.contains(pnt))
587 mEndpointHash[pnt].setOutputPins(netIds, 0, 0);
590 for (
auto itGlOut = mGlobalOutputHash.
constBegin(); itGlOut != mGlobalOutputHash.
constEnd(); ++itGlOut)
593 netIds.
append(itGlOut.key());
594 NetLayoutPoint pnt(mNodeBoundingBox.
right() + 1, 2 * itGlOut.value());
596 if (!mEndpointHash.contains(pnt))
597 mEndpointHash[pnt].setInputPins(netIds, 0, 0);
600 auto it = mJunctionEntries.constBegin();
601 while (it != mJunctionEntries.constEnd() || !mJunctionThreads.isEmpty())
605 if (!it.value().isTrivial())
608 it.value().dumpToFile(it.key());
609 JunctionThread* jt =
new JunctionThread(it.key(), it.value());
611 mJunctionThreads.append(jt);
616 qApp->processEvents();
620 void GraphLayouter::findMaxBoxDimensions()
622 for (
const NodeBox* box : mBoxes)
624 if (box->x() < mMinXIndex)
625 mMinXIndex = box->x();
626 else if (box->x() > mMaxXIndex)
627 mMaxXIndex = box->x();
629 if (box->y() < mMinYIndex)
630 mMinYIndex = box->y();
631 else if (box->y() > mMaxYIndex)
632 mMaxYIndex = box->y();
634 if (mMaxNodeWidth < box->item()->width())
635 mMaxNodeWidth = box->item()->width();
637 if (mMaxNodeHeight < box->item()->height())
638 mMaxNodeHeight = box->item()->height();
640 storeMax(mMaxNodeWidthForX, box->x(), box->item()->width());
641 storeMax(mMaxNodeHeightForY, box->y(), box->item()->height());
643 storeMax(mMaxRightIoPaddingForChannelX, box->x(), box->inputPadding());
644 storeMax(mMaxLeftIoPaddingForChannelX, box->x() + 1, box->outputPadding());
648 void GraphLayouter::findMaxChannelLanes()
651 for (
auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it)
654 unsigned int nw = it.value().size();
655 if (it.key().isHorizontal())
656 mCoordY[pnt.y()].testMinMax(nw);
658 mCoordX[pnt.x()].testMinMax(nw);
664 const NetLayoutPoint& pnt = it.
key();
665 const QRect& rect = it.value()->rect();
666 mCoordX[pnt.x()].testMinMax(rect.
left());
667 mCoordX[pnt.x()].testMinMax(rect.
right());
668 mCoordY[pnt.y()].testMinMax(rect.
top());
669 mCoordY[pnt.y()].testMinMax(rect.
bottom());
674 mCoordX[mNodeBoundingBox.
left()].testMinMax(0);
676 mCoordY[mNodeBoundingBox.
top()].testMinMax(0);
681 auto itx0 = mCoordX.
begin();
682 for (
auto itx1 = itx0 + 1; itx1 != mCoordX.
end(); ++itx1)
684 for (
int x = itx0.key() + 1; x < itx1.key(); x++)
685 mCoordX[x].testMinMax(0);
691 auto ity0 = mCoordY.
begin();
692 for (
auto ity1 = ity0 + 1; ity1 != mCoordY.
end(); ++ity1)
694 for (
int y = ity0.key() + 1; y < ity1.key(); y++)
695 mCoordY[y].testMinMax(0);
701 void GraphLayouter::calculateJunctionMinDistance()
703 for (
auto itJun = mJunctionHash.
constBegin(); itJun != mJunctionHash.
constEnd(); ++itJun)
705 const NetLayoutPoint& pnt0 = itJun.
key();
706 NetLayoutPoint pnt1 = pnt0 +
QPoint(0, 1);
707 const NetLayoutJunction* j1 = mJunctionHash.
value(pnt1);
710 const NetLayoutJunction* j0 = itJun.value();
711 auto itEdp = mEndpointHash.find(pnt1.isEndpoint() ? pnt1 : pnt0);
712 if (itEdp == mEndpointHash.constEnd())
714 float minDistance = 0;
716 if (pnt1.isEndpoint())
719 minDistance = (j0->rect().bottom() + 1) * sLaneSpacing - itEdp.value().lanePosition(j1->rect().top(),
false);
724 minDistance = itEdp.value().lanePosition(j0->rect().bottom(),
false) + (1 - j1->rect().top()) * sLaneSpacing;
726 if (minDistance > mJunctionMinDistanceY[iy])
727 mJunctionMinDistanceY[iy] = minDistance;
731 void GraphLayouter::calculateGateOffsets()
735 for (
auto itSep = mSeparatedWidth.constBegin(); itSep != mSeparatedWidth.constEnd(); itSep++)
737 NetLayoutJunction* jx = mJunctionHash.
value(itSep.key());
740 int ix = itSep.key().x();
741 float xinp = jx->rect().right() * sLaneSpacing + itSep.value().mInputSpace;
742 float xout = itSep.value().mOutputSpace - jx->rect().left() * sLaneSpacing;
743 if (xinp > xInputPadding[ix])
744 xInputPadding[ix] = xinp;
745 if (xout > xOutputPadding[ix])
746 xOutputPadding[ix] = xout;
749 int ix0 = mNodeBoundingBox.
x();
751 float x0 = mCoordX[ix0].preLanes() * sLaneSpacing + sHRoadPadding;
752 if (!mGlobalInputHash.
isEmpty())
754 mCoordX[ix0].setOffset(x0);
755 mCoordX[ix0].setPadding(xInputPadding[ix0]);
759 auto itxLast = mCoordX.
begin();
760 for (
auto itNext = itxLast + 1; itNext != mCoordX.
end(); ++itNext)
763 int ix1 = itNext.key();
767 for (
int ix = ix0; ix < ix1; ix++)
769 auto xn = mMaxNodeWidthForX.
find(ix);
770 if (xn != mMaxNodeWidthForX.
end())
773 itNext->setOffsetX(itxLast.value(), xsum + 2 * sHRoadPadding, xOutputPadding[ix1], xInputPadding[ix1]);
774 mXValues.
append(itNext.value().xBoxOffset());
778 int iy0 = mNodeBoundingBox.
y() * 2;
779 float y0 = mCoordY[iy0].preLanes() * sLaneSpacing + sVRoadPadding;
780 mCoordY[iy0].setOffset(y0);
781 auto ityLast = mCoordY.
begin();
782 for (
auto itNext = ityLast + 1; itNext != mCoordY.
end(); ++itNext)
785 int iy1 = itNext.key();
790 itNext->setOffsetYje(ityLast.value(), mJunctionMinDistanceY.
value(iy1));
795 float ydelta = sVRoadPadding;
796 auto yn = mMaxNodeHeightForY.
find(iy0 / 2);
797 if (yn != mMaxNodeHeightForY.
constEnd())
798 ydelta += yn.
value();
799 itNext->setOffsetYej(ityLast.value(), ydelta, mJunctionMinDistanceY.
value(iy1));
804 iy0 = mNodeBoundingBox.
y() * 2;
805 auto ity = mCoordY.
find(iy0);
806 while(ity != mCoordY.
end())
808 mYValues.
append(ity.value().lanePosition(0));
810 ity = mCoordY.
find(iy0);
814 void GraphLayouter::placeGates()
816 for (
const NodeBox* box : mBoxes)
818 box->item()->setPos(mCoordX[box->x()].xBoxOffset(), mCoordY[box->y() * 2].lanePosition(0));
821 NetLayoutPoint outPnt(box->x() + 1, box->y() * 2);
822 QPointF outPos = box->item()->endpointPositionByIndex(0,
false);
823 mEndpointHash[outPnt].setOutputPosition(outPos);
825 NetLayoutPoint inPnt(box->x(), box->y() * 2);
826 QPointF inPos = box->item()->endpointPositionByIndex(0,
true);
827 mEndpointHash[inPnt].setInputPosition(inPos);
831 for (
auto itEp = mEndpointHash.begin(); itEp != mEndpointHash.end(); ++itEp)
833 if (itEp.value().lanePosition(0,
true) <= 0)
835 float px = mCoordX[itEp.key().x()].lanePosition(-1);
836 float py = mCoordY[itEp.key().y()].lanePosition(0);
837 itEp->setOutputPosition(
QPointF(px, py));
842 void GraphLayouter::drawComments()
844 for (NodeBox* box : mBoxes)
848 CommentSpeechBubble* csb =
new CommentSpeechBubble(
QString(
"%1 [%2]").arg(ce->getHeader()).
arg(ce->getCreationTime().toString(
"dd.MM.yy")),
850 QPointF pos = box->item()->pos() +
QPointF(box->item()->width(),0);
852 mCommentBubbles.append(csb);
857 void GraphLayouter::drawNets()
861 for (
auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it)
864 for (
u32 id : it.value())
865 mLaneMap[
id].insert(it.key(), ilane++);
869 int percentCount = netCount / 93;
877 enum LoopState { LoopInit, CanStartThread, WaitForSlot, WaitForLastThread, LoopDone } loopState = LoopInit;
878 while (loopState != LoopDone)
880 if (mNetIterator != mNetsToDraw.
constEnd())
883 loopState = CanStartThread;
885 loopState = WaitForSlot;
889 if (mDrawNetThreads.isEmpty())
890 loopState = LoopDone;
892 loopState = WaitForLastThread;
895 if (loopState == LoopDone)
898 if (loopState == WaitForLastThread || loopState == WaitForSlot)
900 qApp->processEvents();
904 Q_ASSERT(loopState == CanStartThread);
905 u32 id = *(mNetIterator++);
911 const EndpointList& epl = mWireEndpoint.
value(
id);
912 bool regularNet =
false;
914 switch (epl.netType())
916 case EndpointList::NoEndpoint:
919 case EndpointList::SingleSource:
920 case EndpointList::SingleDestination:
921 case EndpointList::ConstantLevel:
923 drawNetsIsolated(
id,
n, epl);
937 if (doneCount % percentCount == 0)
945 mDrawNetThreads.append(dnt);
950 void GraphLayouter::handleJunctionThreadFinished()
952 JunctionThread* jt =
static_cast<JunctionThread*
>(
sender());
953 mJunctionHash.
insert(jt->mNetLayoutPoint,jt->mJunction);
954 mJunctionThreads.removeAll(jt);
958 void GraphLayouter::handleDrawNetThreadFinished()
962 const EndpointList& epl = mWireEndpoint.
value(dnt->id());
964 GraphicsNet* graphicsNet =
nullptr;
965 switch (epl.netType())
967 case EndpointList::HasGlobalEndpoint:
968 if (epl.hasInputArrow())
970 StandardArrowNet* san =
new StandardArrowNet(
n, dnt->mLines, dnt->mKnots);
972 int yGridPos = mGlobalInputHash.
value(dnt->id(), -1);
973 Q_ASSERT(yGridPos >= 0);
974 QPoint pnt(mNodeBoundingBox.
left(), yGridPos * 2);
975 const EndpointCoordinate& epc = mEndpointHash.value(pnt);
976 const NetLayoutJunction* nlj = mJunctionHash.
value(pnt);
977 san->setInputPosition(
QPointF(mCoordArrayX->lanePosition(mNodeBoundingBox.
left(),nlj?nlj->rect().left():0), epc.lanePosition(0,
true)));
979 if (epl.hasOutputArrow())
982 StandardArrowNet* san =
new StandardArrowNet(
n, dnt->mLines, dnt->mKnots);
984 int yGridPos = mGlobalOutputHash.
value(dnt->id(), -1);
985 Q_ASSERT(yGridPos >= 0);
986 QPoint pnt(mNodeBoundingBox.
right() + 1, yGridPos * 2);
987 const EndpointCoordinate& epc = mEndpointHash.value(pnt);
988 const NetLayoutJunction* nlj = mJunctionHash.
value(pnt);
989 san->setOutputPosition(
QPointF(mCoordArrayX->lanePosition(pnt.x(),nlj?nlj->rect().right():0), epc.lanePosition(0,
true)));
992 case EndpointList::SourceAndDestination:
993 if (dnt->mLines.nLines() > 0)
994 graphicsNet =
new StandardGraphicsNet(
n, dnt->mLines, dnt->mKnots);
1004 mDrawNetThreads.removeAll(dnt);
1008 void GraphLayouter::drawNetsIsolated(
u32 id, Net*
n,
const EndpointList& epl)
1010 SeparatedGraphicsNet* net_item = epl.netType() == EndpointList::ConstantLevel ?
static_cast<SeparatedGraphicsNet*
>(
new LabeledSeparatedNet(
n,
QString::fromStdString(
n->get_name())))
1011 :
static_cast<SeparatedGraphicsNet*
>(
new ArrowSeparatedNet(
n));
1014 for (
const NetLayoutPoint& pnt : epl)
1016 bool isInput = epl.isInput(ipnt++);
1017 auto itPnt = mEndpointHash.find(pnt);
1018 Q_ASSERT(itPnt != mEndpointHash.constEnd());
1022 const NodeBox* nbox = mBoxes.boxForPoint(pnt.gridPoint());
1024 QList<u32> inpList = nbox->item()->inputNets();
1025 for (
int jnx = 0; jnx < inpList.
size(); jnx++)
1027 u32 inpNetId = inpList.
at(jnx);
1030 QPointF inpPnt(itPnt.value().xInput(), itPnt.value().lanePosition(jnx,
true));
1031 net_item->addInput(inpPnt);
1036 for (
int inx : itPnt.value().outputPinIndex(
id))
1038 QPointF outPnt(itPnt.value().xOutput(), itPnt.value().lanePosition(inx,
true));
1039 net_item->addOutput(outPnt);
1043 net_item->finalize();
1047 void GraphLayouter::updateSceneRect()
1053 rect.
adjust(-200, -200, 200, 200);
1057 bool GraphLayouter::boxExists(
const int x,
const int y)
const
1059 return mBoxes.boxForPoint(
QPoint(x, y)) !=
nullptr;
1062 bool GraphLayouter::hRoadJumpPossible(
const int x,
const int y1,
const int y2)
const
1068 int difference = y1 - y2;
1073 difference = y2 - y1;
1078 if (boxExists(x, bottom_y - difference))
1087 bool GraphLayouter::hRoadJumpPossible(
const GraphLayouter::Road*
const r1,
const GraphLayouter::Road*
const r2)
const
1091 assert(r1->x != r2->x);
1093 return hRoadJumpPossible(r1->x, r1->y, r2->y);
1096 bool GraphLayouter::vRoadJumpPossible(
const int x1,
const int x2,
const int y)
const
1102 int difference = x1 - x2;
1107 difference = x2 - x1;
1112 if (boxExists(right_x - difference, y))
1121 bool GraphLayouter::vRoadJumpPossible(
const GraphLayouter::Road*
const r1,
const GraphLayouter::Road*
const r2)
const
1125 assert(r1->y != r2->y);
1127 return vRoadJumpPossible(r1->x, r2->x, r1->y);
1130 qreal GraphLayouter::hRoadHeight(
const unsigned int mLanes)
const
1133 qreal height = sHRoadPadding * 2;
1136 height += (mLanes - 1) * sLaneSpacing;
1141 qreal GraphLayouter::vRoadWidth(
const unsigned int mLanes)
const
1144 qreal width = sVRoadPadding * 2;
1147 width += (mLanes - 1) * sLaneSpacing;
1152 void GraphLayouter::SceneCoordinate::testMinMax(
int ilane)
1154 if (ilane < minLane)
1156 if (ilane + 1 > maxLane)
1157 maxLane = ilane + 1;
1160 void GraphLayouter::SceneCoordinate::setOffsetX(
const SceneCoordinate& previous,
float maximumBlock,
float sepOut,
float sepInp)
1162 float delta = maximumBlock;
1165 mOffset = previous.xBoxOffset() + (1 - minLane) * sLaneSpacing + delta;
1166 float xDefaultBoxPadding = maxLane * sLaneSpacing;
1167 if (xDefaultBoxPadding < sepInp)
1168 mPadding = sepInp - xDefaultBoxPadding;
1171 void GraphLayouter::SceneCoordinate::setOffsetYje(
const SceneCoordinate& previous,
float minimumJunction)
1173 float delta = (previous.maxLane) * sLaneSpacing + sVRoadPadding;
1174 if (delta < minimumJunction)
1175 delta = minimumJunction;
1176 mOffset = previous.mOffset + delta;
1179 void GraphLayouter::SceneCoordinate::setOffsetYej(
const SceneCoordinate& previous,
float maximumBlock,
float minimumJunction)
1181 float delta = (-minLane - 1) * sLaneSpacing + maximumBlock + sVRoadPadding;
1182 if (delta < minimumJunction)
1183 delta = minimumJunction;
1184 mOffset = previous.mOffset + delta;
1187 float GraphLayouter::SceneCoordinate::lanePosition(
int ilane)
const
1189 return mOffset + ilane * sLaneSpacing;
1192 float GraphLayouter::SceneCoordinate::xBoxOffset()
const
1194 return junctionExit() + sHRoadPadding + mPadding;
1198 : mArray(nullptr), mFirstIndex(0)
1202 mArray =
new float[inputMap.
size()];
1204 mFirstIndex = it.
key();
1205 for (
int i = 0; it != inputMap.
constEnd(); ++it)
1207 mArray[i++] = it.value().lanePosition(0);
1212 GraphLayouter::SceneCoordinateArray::~SceneCoordinateArray()
1214 if (mArray)
delete [] mArray;
1217 float GraphLayouter::SceneCoordinateArray::lanePosition(
int igrid,
int ilane)
const
1219 return mArray[igrid-mFirstIndex] + ilane * sLaneSpacing;
1222 float GraphLayouter::EndpointCoordinate::lanePosition(
int ilane,
bool absolute)
const
1224 float y0 = absolute ? mYoffset : mTopPin;
1226 return y0 + ilane * sLaneSpacing;
1227 int n = numberPins() - 1;
1229 return y0 + ilane * mPinDistance;
1230 return y0 +
n * mPinDistance + (ilane -
n) * sLaneSpacing;
1233 GraphLayouter::EndpointCoordinate::EndpointCoordinate() : mYoffset(0), mXoutput(0), mXinput(0), mPinDistance(0), mTopPin(0), mNumberPins(0)
1238 int GraphLayouter::EndpointCoordinate::numberPins()
const
1243 void GraphLayouter::EndpointCoordinate::setInputPosition(
QPointF p0pos)
1245 mXinput = p0pos.
x();
1246 mYoffset = p0pos.
y();
1249 void GraphLayouter::EndpointCoordinate::setOutputPosition(
QPointF p0pos)
1251 mXoutput = p0pos.
x();
1252 if (mXinput < mXoutput)
1254 mYoffset = p0pos.
y();
1257 QList<int> GraphLayouter::EndpointCoordinate::inputPinIndex(
u32 id)
const
1259 return mInputHash.values(
id);
1262 QList<int> GraphLayouter::EndpointCoordinate::outputPinIndex(
u32 id)
const
1264 return mOutputHash.values(
id);
1267 void GraphLayouter::EndpointCoordinate::setInputPins(
const QList<u32>& pinList,
float p0dist,
float pdist)
1269 int n = pinList.
size();
1270 if (
n > mNumberPins)
1272 for (
int i = 0; i <
n; i++)
1274 u32 id = pinList.
at(i);
1276 mInputHash.insert(
id, i);
1278 if (p0dist > mTopPin)
1280 mPinDistance = pdist;
1283 void GraphLayouter::EndpointCoordinate::setOutputPins(
const QList<u32>& pinList,
float p0dist,
float pdist)
1285 int n = pinList.
size();
1286 if (
n > mNumberPins)
1288 for (
int i = 0; i <
n; i++)
1290 u32 id = pinList.
at(i);
1292 mOutputHash.insert(
id, i);
1294 if (p0dist > mTopPin)
1296 mPinDistance = pdist;
1299 void GraphLayouter::EndpointList::addSource(
const NetLayoutPoint& pnt)
1301 mNetType =
static_cast<EndpointType
>(mNetType | SingleSource);
1302 int existingIndex = indexOf(pnt);
1303 if (existingIndex >= 0 && !mPointIsInput.at(existingIndex))
1306 mPointIsInput.append(
false);
1309 void GraphLayouter::EndpointList::addDestination(
const NetLayoutPoint& pnt)
1311 mNetType =
static_cast<EndpointType
>(mNetType | SingleDestination);
1312 int existingIndex = indexOf(pnt);
1313 if (existingIndex >= 0 && mPointIsInput.at(existingIndex))
1316 mPointIsInput.append(
true);
1319 void GraphLayouter::SeparatedNetWidth::requireInputSpace(
float spc)
1321 if (spc > mInputSpace)
1325 void GraphLayouter::SeparatedNetWidth::requireOutputSpace(
float spc)
1327 if (spc > mOutputSpace)
1331 bool GraphLayouter::isConstNet(
const Net*
n)
1333 for (Endpoint* src :
n->get_sources())
1335 if (src->get_gate()->is_gnd_gate() || src->get_gate()->is_vcc_gate())
1343 return mDumpJunctions;
1348 mDumpJunctions = enabled;
1369 int ilane = it.value();
1370 int ix0 = wFromPoint.
x();
1371 int iy0 = wFromPoint.
y();
1372 int ix1 = wToPoint.
x();
1373 int iy1 = wToPoint.
y();
1375 if (it.key().isHorizontal())
1377 float x0 = mLayouter->mCoordArrayX->lanePosition(ix0,j0? j0->
rect().
right() : 0);
1378 float x1 = mLayouter->mCoordArrayX->lanePosition(ix1,j1? j1->
rect().
left() : 0);
1379 float yy = mLayouter->mCoordArrayY->lanePosition(iy0,ilane);
1385 float xx = mLayouter->mCoordArrayX->lanePosition(ix0,ilane);
1389 auto itEpc = mLayouter->mEndpointHash.find(wToPoint);
1390 y0 = mLayouter->mCoordArrayY->lanePosition(iy0, j0? j0->
rect().
bottom() : 0);
1391 y1 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j1 ? j1->
rect().
top() : 0,
true)
1392 : mLayouter->mCoordArrayY->lanePosition(iy1,0);
1397 auto itEpc = mLayouter->mEndpointHash.find(wFromPoint);
1398 y0 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j0 ? j0->
rect().
bottom() : 0,
true)
1399 : mLayouter->mCoordArrayY->lanePosition(iy0,0);
1400 y1 = mLayouter->mCoordArrayY->lanePosition(iy1, j1? j1->
rect().
top() : 0);
1410 void DrawNetThread::drawJunction()
1412 for (
auto jt = mLayouter->mJunctionHash.
constBegin(); jt != mLayouter->mJunctionHash.
constEnd(); ++jt)
1414 auto epcIt = mLayouter->mEndpointHash.find(jt.key());
1415 int x = jt.key().x();
1416 int y = jt.key().y();
1417 bool isEndpoint = (y % 2 == 0);
1421 int li = jw.mIndex.laneIndex();
1422 if (jw.mIndex.isHorizontal())
1424 Q_ASSERT(epcIt != mLayouter->mEndpointHash.constEnd() || !isEndpoint);
1425 float x0 = mLayouter->mCoordArrayX->lanePosition(x,jw.mRange.first());
1426 float x1 = mLayouter->mCoordArrayX->lanePosition(x,jw.mRange.last());
1427 float yy = isEndpoint ? epcIt.value().lanePosition(li,
true) : mLayouter->mCoordArrayY->lanePosition(y,li);
1435 y0 = mLayouter->mCoordArrayY->lanePosition(y,jw.mRange.first());
1436 y1 = mLayouter->mCoordArrayY->lanePosition(y,jw.mRange.last());
1438 else if (epcIt != mLayouter->mEndpointHash.constEnd())
1440 y0 = epcIt.value().lanePosition(jw.mRange.first(),
true);
1441 y1 = epcIt.value().lanePosition(jw.mRange.last(),
true);
1445 y0 = mLayouter->mCoordY.
value(y).junctionEntry();
1446 y1 = mLayouter->mCoordY.
value(y).junctionExit();
1450 float xx = mLayouter->mCoordArrayX->lanePosition(x,li);
1455 for (
const QPoint& pnt : jt.value()->netById(mId).mKnots)
1457 float xp = mLayouter->mCoordArrayX->lanePosition(x,pnt.x());
1458 float yp = isEndpoint ? epcIt.value().lanePosition(pnt.y(),
true) : mLayouter->mCoordArrayY->lanePosition(y,pnt.y());
1464 void DrawNetThread::drawEndpoint()
1466 for (
auto it = mLayouter->mEndpointHash.constBegin(); it != mLayouter->mEndpointHash.constEnd(); ++it)
1468 const GraphLayouter::EndpointCoordinate& epc = it.value();
1470 QList<int> inputsById = epc.inputPinIndex(mId);
1471 QList<int> outputsById = epc.outputPinIndex(mId);
1475 const NetLayoutJunction* nlj = mLayouter->mJunctionHash.
value(it.key());
1476 int ix = it.key().x();
1477 float xjLeft = mLayouter->mCoordArrayX->lanePosition(ix,nlj?nlj->rect().left():0);
1478 float xjRight = mLayouter->mCoordArrayX->lanePosition(ix,nlj?nlj->rect().right():0);
1480 for (
int inpInx : inputsById)
1482 if (xjRight >= epc.xInput())
1485 auto ityOut = mLayouter->mGlobalOutputHash.
find(mId);
1486 if (ityOut == mLayouter->mGlobalOutputHash.
constEnd() ||
QPoint(mLayouter->mNodeBoundingBox.
right() + 1, 2 * ityOut.value()) != it.key())
1487 qDebug() <<
"cannot connect input pin" << mId << it.key().x() << it.key().y() / 2 << xjRight << epc.xInput();
1492 for (
int outInx : outputsById)
1494 if (epc.xOutput() >= xjLeft)
1495 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
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)