diff --git a/plugins/gui/include/gui/graph_widget/graph_context_manager.h b/plugins/gui/include/gui/graph_widget/graph_context_manager.h index a0e84ba974a..494e14bddfc 100644 --- a/plugins/gui/include/gui/graph_widget/graph_context_manager.h +++ b/plugins/gui/include/gui/graph_widget/graph_context_manager.h @@ -394,7 +394,7 @@ namespace hal u32 mMaxContextId; void dump(const QString& title, u32 mid, u32 xid) const; SettingsItemCheckbox* mSettingDebugGrid; - SettingsItemCheckbox* mSettingNetLayout; + SettingsItemCheckbox* mSettingDumpJunction; SettingsItemCheckbox* mSettingParseLayout; SettingsItemCheckbox* mSettingLayoutBoxes; }; diff --git a/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h b/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h index 3ce91f2e26d..dcd374af447 100644 --- a/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h +++ b/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h @@ -47,7 +47,7 @@ namespace hal { * @param n - The underlying net * @param l - The lines this GraphicsNet consists of */ - StandardArrowNet(Net* n, const Lines& l); + StandardArrowNet(Net* n, const Lines& l, const QList& knots = QList()); /** * Adds an input position. * diff --git a/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h b/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h index 85cc07e027d..1204abaa21a 100644 --- a/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h +++ b/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h @@ -93,11 +93,6 @@ namespace hal */ void appendVLine(const qreal x, const qreal mSmallY, const qreal mBigY); - /** - * Merges all horizontal and vertical lines so that overlapping lines are replaced by only a single line. - */ - void mergeLines(); - /** * Gets the total amount of lines (includes horizontal AND vertical lines). * @@ -129,7 +124,7 @@ namespace hal * @param n - The undelying net of the StandardGraphicsNet * @param l - The lines this GraphicsNet consists of */ - StandardGraphicsNet(Net* n, const Lines& l); + StandardGraphicsNet(Net* n, const Lines& l, const QList& knots = QList()); /** * Draws the StandardGraphicsNet in the scene. diff --git a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h index ffca73fa902..9324227d717 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h +++ b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h @@ -43,6 +43,7 @@ #include #include #include +#include namespace hal { @@ -59,6 +60,8 @@ namespace hal class NetLayoutJunctionEntries; class CommentSpeechBubble; class CommentEntry; + class JunctionThread; + class DrawNetThread; /** * @ingroup graph-layouter @@ -75,6 +78,8 @@ namespace hal { Q_OBJECT + friend class DrawNetThread; + class SceneCoordinate { int minLane; @@ -115,6 +120,16 @@ namespace hal float xBoxOffset() const; }; + class SceneCoordinateArray + { + float* mArray; + int mFirstIndex; + public: + SceneCoordinateArray(const QMap& inputMap); + ~SceneCoordinateArray(); + float lanePosition(int igrid, int ilane) const; + }; + class EndpointCoordinate { float mYoffset; @@ -203,48 +218,10 @@ namespace hal unsigned int mLanes = 0; }; - struct Junction - { - Junction(const int x_coordinate, const int y_coordinate) - : x(x_coordinate), y(y_coordinate), mHLanes(0), mVLanes(0), mCloseLeftLaneChanges(0), mCloseRightLaneChanges(0), mCloseTopLaneChanges(0), mCloseBottomLaneChanges(0), - mFarLeftLaneChanges(0), mFarRightLaneChanges(0), mFarTopLaneChanges(0), mFarBottomLaneChanges(0) - { - } - - int x; - int y; - - unsigned int mHLanes = 0; - unsigned int mVLanes = 0; - - unsigned int mCloseLeftLaneChanges = 0; - unsigned int mCloseRightLaneChanges = 0; - unsigned int mCloseTopLaneChanges = 0; - unsigned int mCloseBottomLaneChanges = 0; - - unsigned int mFarLeftLaneChanges = 0; - unsigned int mFarRightLaneChanges = 0; - unsigned int mFarTopLaneChanges = 0; - unsigned int mFarBottomLaneChanges = 0; - }; - struct UsedPaths { QSet mHRoads; QSet mVRoads; - - QSet mHJunctions; - QSet mVJunctions; - - QSet mCloseLeftJunctions; - QSet mCloseRightJunctions; - QSet mCloseTopJunctions; - QSet mCloseBottomJunctions; - - QSet mFarLeftJunctions; - QSet mFarRightJunctions; - QSet mFarTopJunctions; - QSet mFarBottomJunctions; }; public: @@ -309,8 +286,8 @@ namespace hal bool done() const; - bool optimizeNetLayoutEnabled(); - void setOptimizeNetLayoutEnabled(bool enbabled); + bool dumpJunctionEnabled(); + void setDumpJunctionEnabled(bool enabled); QVector xValues() const; QVector yValues() const; @@ -340,27 +317,22 @@ namespace hal QMap mPositionToNodeMap; QMap mNodeToPositionRollback; + private Q_SLOTS: + void handleDrawNetThreadFinished(); + void handleJunctionThreadFinished(); + private: void clearLayoutData(); void clearComments(); void createBoxes(); - void calculateNets(); void getWireHash(); void findMaxBoxDimensions(); - void alternateMaxChannelLanes(); void findMaxChannelLanes(); - void calculateMaxChannelDimensions(); void calculateJunctionMinDistance(); - void alternateGateOffsets(); void calculateGateOffsets(); - void alternatePlaceGates(); void placeGates(); - void resetRoadsAndJunctions(); void drawNets(); - void alternateDrawNets(); void drawComments(); - void drawNetsJunction(StandardGraphicsNet::Lines& lines, u32 id); - void drawNetsEndpoint(StandardGraphicsNet::Lines& lines, u32 id); void drawNetsIsolated(u32 id, Net* n, const EndpointList& epl); void updateSceneRect(); static bool verifyModulePort(Net* n, const Node& modNode, bool isModInput); @@ -375,72 +347,19 @@ namespace hal bool vRoadJumpPossible(const int x1, const int x2, const int y) const; bool vRoadJumpPossible(const Road* const r1, const Road* const r2) const; - Road* getHRoad(const int x, const int y); - Road* getVRoad(const int x, const int y); - Junction* getJunction(const int x, const int y); - qreal hRoadHeight(const unsigned int mLanes) const; qreal vRoadWidth(const unsigned int mLanes) const; - qreal sceneYForHChannelLane(const int y, const unsigned int lane) const; - qreal sceneXForVChannelLane(const int x, const unsigned int lane) const; - - qreal sceneXForCloseLeftLaneChange(const int channel_x, unsigned int lane_change) const; - qreal sceneXForFarLeftLaneChange(const int channel_x, unsigned int lane_change) const; - - qreal sceneXForCloseRightLaneChange(const int channel_x, unsigned int lane_change) const; - qreal sceneXForFarRightLaneChange(const int channel_x, unsigned int lane_change) const; - - qreal sceneYForCloseTopLaneChange(const int channel_y, unsigned int lane_change) const; - qreal sceneYForFarTopLaneChange(const int channel_y, unsigned int lane_change) const; - - qreal sceneYForCloseBottomLaneChange(const int channel_y, unsigned int lane_change) const; - qreal sceneYForFarBottomLaneChange(const int channel_y, unsigned int lane_change) const; - - qreal sceneXForCloseLeftLaneChange(const Junction* const j) const; - qreal sceneXForFarLeftLaneChange(const Junction* const j) const; - - qreal sceneXForCloseRightLaneChange(const Junction* const j) const; - qreal sceneXForFarRightLaneChange(const Junction* const j) const; - - qreal sceneYForCloseTopLaneChange(const Junction* const j) const; - qreal sceneYForFarTopLaneChange(const Junction* const j) const; - - qreal sceneYForCloseBottomLaneChange(const Junction* const j) const; - qreal sceneYForFarBottomLaneChange(const Junction* const j) const; - - void commitUsedPaths(const UsedPaths& used); static bool isConstNet(const Net* n); NodeBoxes mBoxes; - QHash mHRoads; - QHash mVRoads; - QHash mJunctions; - QMap mMaxNodeWidthForX; QMap mMaxNodeHeightForY; - QMap mMaxVChannelLanesForX; - QMap mMaxHChannelLanesForY; - - QMap mMaxVChannelLeftSpacingForX; - QMap mMaxVChannelRightSpacingForX; - QMap mMaxHChannelTopSpacingForY; - QMap mMaxHChannelBottomSpacingForY; - - QMap mMaxVChannelWidthForX; - QMap mMaxHChannelHeightForY; - QMap mNodeOffsetForX; QMap mNodeOffsetForY; - QMap mMaxLeftJunctionSpacingForX; - QMap mMaxRightJunctionSpacingForX; - - QMap mMaxTopJunctionSpacingForY; - QMap mMaxBottomJunctionSpacingForY; - QMap mMaxLeftIoPaddingForChannelX; QMap mMaxRightIoPaddingForChannelX; @@ -477,7 +396,42 @@ namespace hal QHash mGlobalInputHash; QHash mGlobalOutputHash; - bool mOptimizeNetLayout; + bool mDumpJunctions; QList mCommentBubbles; + QSet mNetsToDraw; + QSet::const_iterator mNetIterator; + QList mDrawNetThreads; + QList mJunctionThreads; + QHash> mLaneMap; + + SceneCoordinateArray* mCoordArrayX; + SceneCoordinateArray* mCoordArrayY; + }; + + class DrawNetThread : public QThread + { + Q_OBJECT + u32 mId; + GraphLayouter* mLayouter; + void drawJunction(); + void drawEndpoint(); + public: + StandardGraphicsNet::Lines mLines; + QList mKnots; + DrawNetThread(u32 id, GraphLayouter* parent) : QThread(parent), mId(id), mLayouter(parent) {;} + u32 id() const { return mId; } + void run() override; + }; + + class JunctionThread : public QThread + { + Q_OBJECT + public: + NetLayoutPoint mNetLayoutPoint; + NetLayoutJunctionEntries mEntries; + NetLayoutJunction* mJunction; + JunctionThread(const NetLayoutPoint& nlp, const NetLayoutJunctionEntries& entr) + : mNetLayoutPoint(nlp), mEntries(entr), mJunction(nullptr) {;} + void run() override; }; } // namespace hal diff --git a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h index 70b05eaacdf..4cb5d01d650 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h +++ b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h @@ -1,28 +1,3 @@ -// MIT License -// -// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. -// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. -// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. -// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - #pragma once #include @@ -32,142 +7,393 @@ #include #include #include -#include "net_layout_point.h" +#include "gui/graph_widget/layouters/net_layout_point.h" + +// #define JUNCTION_DEBUG = 1 class QGraphicsEllipseItem; class QGraphicsLineItem; class QGraphicsScene; -QColor colorFromId(u32 netId); +const int DELTA = 20; +const int FIRST = 400; +const int GAP = 200; namespace hal { /** - * @ingroup gui + * Condensed lane index comprises information whether road is horizontal or vertical + * + * @ingroup graph-layouter */ - class NetLayoutJunctionWireIntersection : public QPoint + class LaneIndex { - bool mValid; + friend uint qHash(const LaneIndex& ri); + int mIndex; public: - NetLayoutJunctionWireIntersection(bool valid=false, int x_=0, int y_=0) - : QPoint(x_,y_), mValid(valid) {;} - enum PlacementType { Normal, Verify, Endpoint }; - bool isValid() const { return mValid; } - QGraphicsEllipseItem* graphicsFactory(u32 netId) const; + enum HVIndex { Horizontal, Vertical }; + + /** + * Constructor + * @param ihv Horizontal or Vertical + * @param ilane Lane index + */ + LaneIndex(HVIndex ihv, int ilane) : mIndex(ihv | (ilane << 1)) {;} + + /** + * Cast to integer, mainly used as index + */ + operator int () const { return mIndex; } + + /** + * Increment to next parallel lane + * @return The incremented index + */ + LaneIndex& operator++() { mIndex += 2; return *this; } + + /** + * Decrement to previous parallel lane + * @return The decremented index + */ + LaneIndex& operator--() { mIndex -= 2; return *this; } + + /** + * Getter for road direction + * @return Horizontal or Vertical + */ + HVIndex hvIndex() const { return (HVIndex) (mIndex & 1); } + + /** + * Getter for lane index + * @return The index (might be negative) + */ + int laneIndex() const { return (mIndex >> 1); } + + /** + * Convenience method to check whether road direction is horizontal + * @return true if horizontal, false otherwise + */ + bool isHorizontal() const { return hvIndex() == Horizontal; } + + /** + * Convenience method to check whether road direction is vertical + * @return true if vertical, false otherwise + */ + bool isVertical() const { return hvIndex() == Vertical; } + + /** + * Construct horizontal lane + * @param ilane - lane index + */ + static LaneIndex horizontal(int ilane) { return LaneIndex(Horizontal,ilane); } + + /** + * Construct vertical lane + * @param ilane - lane index + */ + static LaneIndex vertical(int ilane) { return LaneIndex(Vertical,ilane); } }; + class NetLayoutJunctionWire; + /** + * Range including first and last grid point (potentially) on lane used by net id. + * External nets leading to junction start at MinInf or MaxInf. + * * @ingroup graph-layouter */ - class NetLayoutJunctionWire + class NetLayoutJunctionRange { - public: - int mHorizontal; - int mRoad; + u32 mNetId; int mFirst; int mLast; - NetLayoutJunctionWire(int hor, int rd, int fir, int las) - : mHorizontal(hor), mRoad(rd), mFirst(fir), mLast(las) {;} - NetLayoutJunctionWireIntersection intersection(const NetLayoutJunctionWire& other) const; - bool isEntry() const; - int centralEnd() const; + public: + static const int MinInf = -32767; + static const int MaxInf = 32767; + + NetLayoutJunctionRange(u32 netId_, int first, int last); + + /** + * Check whether range instance would overlap with instance from other net + * @param other Possibly conflicting range + * @return true if nets are different and share at least a common point, false otherwise + */ + bool conflict(const NetLayoutJunctionRange& other) const; + + /** + * Checks whether position is within range including first and last grid point + * @param pos Relevant coordinate from grid point to check + * @return true if in range according to condition above, false otherwise + */ + bool contains(int pos) const { return mFirst <= pos && pos <= mLast; } + + /** + * Checks whether position is within range excluding first and last grid point + * @param pos Relevant coordinate from grid point to check + * @return true if in range according to condition above, false otherwise + */ + bool innerPos(int pos) const { return mFirst < pos && pos < mLast; } + + /** + * Checks whether ranges of same net can be joined to bigger range + * @param other Range which might be joined + * @return true if range can be joined, false otherwise + */ + bool canJoin(const NetLayoutJunctionRange& other) const; + + /** + * Checks whether range is entry from external net + * @param iTestMax Test for MinInf if 0, MaxInf otherwise + * @return true if range is entry from external net + */ + bool isEntry(int iTestMax) const; + + /** + * Checks whether two ranges are equal + */ + bool operator==(const NetLayoutJunctionRange& other) const; + + /** + * Checks whether range from wire is equal with this range + */ + bool operator==(const NetLayoutJunctionWire& wire) const; + + /** + * Getter for net ID + * @return the net ID + */ + u32 netId() const { return mNetId; } + + /** + * Getter for first grid point position in range + * @return the first grid point position in range + */ + int first() const { return mFirst; } + + /** + * Setter for first grid point position in range + * @param fst the new first grid point position in range + */ + void setFirst(int fst) { mFirst = fst; } + + /** + * Getter for last grid point position in range + * @return the last grid point position in range + */ + int last() const { return mLast; } + + /** + * Setter for last grid point position in range + * @param lst the new last grid point position in range + */ + void setLast(int lst) { mLast = lst; } + + /** + * Getter for the difference between first and last grid point of range + * @return the differnce between first and last + */ + int length() const { return mLast-mFirst; } + + /** + * Getter for the first or last grid position in range + * @param iGetLast get first position if 0, last positon otherwise + * @return the first or last grid position in range + */ + int endPosition(int iGetLast) const; + + /** + * Expand the range by joining other range + * @param other The other range + */ + void expand(const NetLayoutJunctionRange& other); + + /** + * Return range parameter as human readable string + * @return The string + */ + QString toString() const { return QString("<%1|%2..%3>").arg(mNetId).arg(mFirst).arg(mLast); } + + /** + * Generate an entry range + * @param dir Direction (Left, Right, Up, Down) + * @param ilane Lane index + * @param netId Net ID + * @return The range + */ + static NetLayoutJunctionRange entryRange(NetLayoutDirection dir, int ilane, u32 netId); }; /** + * Single straight wire located in a range of a lane + * * @ingroup graph-layouter */ + class NetLayoutJunctionWire + { + public: + /** + * Lane index + */ + LaneIndex mIndex; + + /** + * Range including net id + */ + NetLayoutJunctionRange mRange; + + /** + * constructor + */ + NetLayoutJunctionWire(const NetLayoutJunctionRange& rng, const LaneIndex& li) + : mIndex(li), mRange(rng) {;} + + /** + * Checks whether wire is entry from external net + * @return true if wire is entry from external net, false otherwise + */ + bool isEntry() const; + }; + + /** + * List of nets entering the junction sorted by entry direction + */ class NetLayoutJunctionEntries { - friend class NetLayoutJunction; - protected: - QList mEntries[4]; public: - int size(NetLayoutDirection dir) const { return mEntries[dir.index()].size(); } - u32 id(NetLayoutDirection dir, int i) const { return mEntries[dir.index()].at(i); } - QString dump() const; - void dumpFile(const NetLayoutPoint& pnt) const; - void setEntries(NetLayoutDirection dir, const QList& entries_); + /** + * Entries sorted by direction (Left, Right, Up, Down) + */ + QList mEntries[4]; + + /** + * Get net ID from junction entry list / array + * @param dir Direction (Left, Right, Up, Down) + * @param ilane Lane index + * @return Net ID + */ + u32 id(NetLayoutDirection dir, int ilane) const { return mEntries[dir.index()].at(ilane); } + + /** + * String output for debugging purpose + */ + QString toString() const; + + /** + * Dump junction entries to file to debug junction routing + * @param pnt Net grid point + */ + void dumpToFile(const QPoint& pnt) const; + + static QString gridPointName(const QPoint& p); }; + /** + * Connection more than one gate pin with the same wire + */ class NetLayoutJunctionMultiPin { public: - int mRoad; + /** + * The lane connecting the gate which was routed first + */ + int mLane; + + /** + * Other lanes (except mLane) connecting the net with the gate + */ QList mConnector; - NetLayoutJunctionMultiPin() : mRoad(-1) {} - void setRoad(int road) { mRoad = road; } + + /** + * Constructor + */ + NetLayoutJunctionMultiPin() : mLane(-1) {} }; /** + * @brief Single net to be routed through the junction + * + * At this point there can only be one entry point for each given direction. * @ingroup graph-layouter */ class NetLayoutJunctionNet { - u32 mPattern; - int mRoadNumber[4]; // index: Left = 0, Right = 1, Up = 2, Down = 3 value: -1 = unused + u32 mPattern; // binary pattern + int mLaneIndex[4]; // index: Left = 0, Right = 1, Up = 2, Down = 3 value: -1 = unused int mEntries; bool mPlaced; - NetLayoutJunctionWireIntersection mJunction; public: QList mWires; + QList mKnots; NetLayoutJunctionNet(); - void addEntry(NetLayoutDirection dir, int roadNo); + void addEntry(NetLayoutDirection dir, int laneInx); QString toString() const; + + /** + * Check whether search pattern is included in binary pattern + * @param searchPattern Combination of Left (bit 0), Right (bit 1), Up (bit 2), Down (bit 3) + * @return true if search pattern is included in binary pattern, false otherwise + */ bool hasPattern(u32 searchPattern) const; - int roadNumber(NetLayoutDirection dir) const { return mRoadNumber[dir.index()]; } + int laneIndex(NetLayoutDirection dir) const { return mLaneIndex[dir.index()]; } int numberEntries() const { return mEntries; } u32 pattern() const { return mPattern; } void setPattern(u32 pat) { mPattern = pat; } bool isPlaced() const { return mPlaced; } + QList wireAtPos(int pos, LaneIndex::HVIndex hvi); void setPlaced() { mPlaced = true; } void addWire(const NetLayoutJunctionWire& wire) { mWires.append(wire); } - NetLayoutJunctionWireIntersection junctionPoint() const { return mJunction; } - void setJunctionPoint(const NetLayoutJunctionWireIntersection& jp, - NetLayoutJunctionWireIntersection::PlacementType placement - = NetLayoutJunctionWireIntersection::Normal); + void replaceWire(const NetLayoutJunctionRange& rng, const NetLayoutJunctionWire& wire); + QList junctionKnots() const { return mKnots; } }; /** * @ingroup graph-layouter */ - class NetLayoutJunctionRange + class NetLayoutJunctionOccupied : public QList { - u32 mNetId; - int mFirst; - int mLast; public: - static const int sMinInf = -32767; - static const int sMaxInf = 32767; - static const int sSceneDelta = 20; - static const int sSceneFirst = 400; - static const int sSceneGap = 200; - NetLayoutJunctionRange(u32 netId_, int first, int last); - - NetLayoutJunctionWire toWire(int hor, int rd) const; - bool conflict(const NetLayoutJunctionRange& other) const; + bool conflict(const NetLayoutJunctionRange& test) const; bool canJoin(u32 netId, int pos) const; - bool canJoin(const NetLayoutJunctionRange& other) const; - u32 netId() const { return mNetId; } - int endPosition(int inx) const; - bool isEntry(int inx) const; - int graphFirst() const; - int graphLast() const; - bool operator==(const NetLayoutJunctionRange& other) const; - void expand(const NetLayoutJunctionRange& other); - static NetLayoutJunctionRange entryRange(NetLayoutDirection dir, int iroad, u32 netId); }; /** * @ingroup graph-layouter */ - class NetLayoutJunctionOccupied : public QList + class NetLayoutJunctionOccupiedHash : public QHash { public: - bool conflict(const NetLayoutJunctionRange& test) const; - bool canJoin(u32 netId, int pos) const; - void add(const NetLayoutJunctionRange& rng); + /** + * Result class for addOrMerge() function + * If range was merged, old and new range will be returned + * otherwise these values are not set (nullptr) + */ + class AddOrMerge + { + public: + enum Type { Added, Merged, AlreadyExisting } mType; + NetLayoutJunctionRange* mOldRange; + NetLayoutJunctionRange* mNewRange; + AddOrMerge() : mType(Added), mOldRange(nullptr), mNewRange(nullptr) {;} + ~AddOrMerge() + { + if (mOldRange) delete mOldRange; + if (mNewRange) delete mNewRange; + } + }; + + /** + * Adds new entry for range or merges it + * @param ri Road index where to add + * @param rng Range to add + * @return see AddType above. + */ + AddOrMerge addOrMerge(const LaneIndex &ri, const NetLayoutJunctionRange& rng); + +#ifdef JUNCTION_DEBUG + QList> mHistory; +#endif }; /** @@ -179,44 +405,64 @@ namespace hal { NetLayoutJunction(const NetLayoutJunctionEntries& entries); ~NetLayoutJunction() {;} QRect rect() const { return mRect; } - void dump() const; - NetLayoutJunctionNet netById(u32 id) const { return mNetsOutput.value(id); } - enum mErrorT {StraightRouteError = -2, CornerRouteError = -1, Ok = 0 }; - mErrorT lastError() const { return mError; } + NetLayoutJunctionNet netById(u32 id) const { return mNets.value(id); } + + enum ErrorType {StraightRouteError = -3, TRouteError = -2, CornerRouteError = -1, Ok = 0 }; + ErrorType lastError() const { return mError; } + +#ifdef JUNCTION_DEBUG + void toScene(QGraphicsScene* scene) const; + void toSceneStep(QGraphicsScene* scene, int istep); + int numberSteps() const { return mOccupied.mHistory.size(); } +#endif private: - void fourWayJunctions(QHash::iterator& netIt); void routeT(); void routeAllStraight(NetLayoutDirection dirFrom, NetLayoutDirection dirTo); void routeAllCorner(NetLayoutDirection dirHoriz, NetLayoutDirection dirVertic); void routeSingleStraight(u32 netId, int iMain, int iroadIn, int iroadOut); - void routeSingleDetour(u32 netId, int iMain, int iroadIn, int iroadOut); + void routeSingleSwap(u32 netId, int iMain, int iroadIn, int iroadOut); void routeSingleCorner(u32 netId, NetLayoutDirection dirHoriz, NetLayoutDirection dirVertic); + + /** + * Connect nets with multiple pins at same node + * @param leftOrRight whether Node is to the left or right of node + */ void routeAllMultiPin(NetLayoutDirection leftOrRight); + + /** + * Connect a single node where + * @param netId + * @param leftOrRight + * @param nmpin + */ void routeSingleMultiPin(u32 netId, NetLayoutDirection leftOrRight, const NetLayoutJunctionMultiPin &nmpin); + void findJunctions(); void calculateRect(); - bool conflict(int ihoriz, int iroad, const NetLayoutJunctionRange& testRng) const; - void place(int ihoriz, int iroad, const NetLayoutJunctionRange& range); - bool canJoin(int ihoriz, int iroad, u32 netId, int pos) const; - int* canJoinAny(int ihoriz, u32 netId, int pos) const; + bool conflict(const LaneIndex& ri, const NetLayoutJunctionRange& testRng) const; + void place(const LaneIndex& ri, const NetLayoutJunctionRange& range); + bool canJoin(const LaneIndex& ri, u32 netId, int pos) const; QRect mRect; NetLayoutJunctionEntries mEntries; - QHash mNetsInput; - QHash mNetsOutput; - QHash mOccupied[2]; // 0=horizontal, 1=vertical + QHash mNets; + NetLayoutJunctionOccupiedHash mOccupied; int maxRoad[2]; - mErrorT mError; + ErrorType mError; }; - /** - * @ingroup graph-layouter - */ class NetLayoutJunctionHash : public QHash { public: - NetLayoutJunctionHash() {;} - ~NetLayoutJunctionHash(); + NetLayoutJunctionHash() = default; + ~NetLayoutJunctionHash() = default; void clearAll(); }; + + uint qHash(const LaneIndex& ri); } +#ifdef JUNCTION_DEBUG + void setColorMap(const hal::NetLayoutJunctionEntries& entries); + QColor colorFromId(u32 netId); +#endif + diff --git a/plugins/gui/include/gui/graph_widget/layouters/net_layout_point.h b/plugins/gui/include/gui/graph_widget/layouters/net_layout_point.h index 1bb753d6dc7..1bb0eaaa8dd 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/net_layout_point.h +++ b/plugins/gui/include/gui/graph_widget/layouters/net_layout_point.h @@ -102,6 +102,7 @@ namespace hal { bool isEndpoint() const { return mIsEndpoint; } bool isHorizontal() const { return mDir.isHorizontal(); } bool operator==(const NetLayoutWire& other) const; + QString toString() const; private: NetLayoutPoint mPoint; NetLayoutDirection mDir; @@ -151,7 +152,6 @@ namespace hal { public: NetLayoutConnectionFactory(const QList& sources, const QList& destinations); QList points() const { return mPoints; } - QList mJunctions; NetLayoutConnection* connection; void dump(const QString& stub) const; private: diff --git a/plugins/gui/src/graph_widget/graph_context_manager.cpp b/plugins/gui/src/graph_widget/graph_context_manager.cpp index 4e6b888afda..a0be39acec9 100644 --- a/plugins/gui/src/graph_widget/graph_context_manager.cpp +++ b/plugins/gui/src/graph_widget/graph_context_manager.cpp @@ -38,7 +38,11 @@ namespace hal "eXpert Settings:Debug", "Specifies whether the debug grid is displayed in the Graph View. The gird represents the scene as the layouter interprets it."); - mSettingNetLayout = new SettingsItemCheckbox("Optimize Net Layout", "graph_view/layout_nets", true, "Graph View", "Net optimization - not fully tested yet."); + mSettingDumpJunction = new SettingsItemCheckbox("Dump Junction Data", + "debug/junction", + false, + "eXpert Settings:Debug", + "Dump input data from junction router to file 'junction_data.txt' for external debugging."); mSettingParseLayout = new SettingsItemCheckbox("Apply Parsed Position", "graph_view/layout_parse", true, "Graph View", "Use parsed verilog coordinates if available."); @@ -512,11 +516,11 @@ namespace hal GraphLayouter* GraphContextManager::getDefaultLayouter(GraphContext* const context) const { StandardGraphLayouter* layouter = new StandardGraphLayouter(context); - layouter->setOptimizeNetLayoutEnabled(mSettingNetLayout->value().toBool()); + layouter->setDumpJunctionEnabled(mSettingDumpJunction->value().toBool()); layouter->setParseLayoutEnabled(mSettingParseLayout->value().toBool()); layouter->setLayoutBoxesEnabled(mSettingLayoutBoxes->value().toBool()); - connect(mSettingNetLayout, &SettingsItemCheckbox::boolChanged, layouter, &GraphLayouter::setOptimizeNetLayoutEnabled); + connect(mSettingDumpJunction, &SettingsItemCheckbox::boolChanged, layouter, &GraphLayouter::setDumpJunctionEnabled); connect(mSettingParseLayout, &SettingsItemCheckbox::boolChanged, layouter, &StandardGraphLayouter::setParseLayoutEnabled); connect(mSettingLayoutBoxes, &SettingsItemCheckbox::boolChanged, layouter, &StandardGraphLayouter::setLayoutBoxesEnabled); diff --git a/plugins/gui/src/graph_widget/items/nets/standard_arrow_net.cpp b/plugins/gui/src/graph_widget/items/nets/standard_arrow_net.cpp index f7f91750de8..25251225ba8 100644 --- a/plugins/gui/src/graph_widget/items/nets/standard_arrow_net.cpp +++ b/plugins/gui/src/graph_widget/items/nets/standard_arrow_net.cpp @@ -2,8 +2,8 @@ namespace hal { - StandardArrowNet::StandardArrowNet(Net* n, const Lines &l) - : StandardGraphicsNet(n,l), mArrowNet(n) + StandardArrowNet::StandardArrowNet(Net* n, const Lines &l, const QList& knots) + : StandardGraphicsNet(n,l,knots), mArrowNet(n) {;} void StandardArrowNet::setInputPosition(const QPointF& pos) diff --git a/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp b/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp index 9ed8199b9c4..11da9520887 100644 --- a/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp +++ b/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include namespace hal { @@ -73,28 +76,12 @@ namespace hal sAlpha = 1; } - StandardGraphicsNet::StandardGraphicsNet(Net* n, const Lines& l) : GraphicsNet(n) + StandardGraphicsNet::StandardGraphicsNet(Net* n, const Lines& l, const QList &knots) : GraphicsNet(n) { - for (const HLine& h : l.mHLines) + for (const QPointF& point : knots) { - for (const VLine& v : l.mVLines) - { - if (h.mSmallX <= v.x && v.x <= h.mBigX) - if (v.mSmallY < h.y && h.y < v.mBigY) - { - QPointF point(v.x, h.y); - mSplits.append(point); - mShape.addEllipse(point, sSplitRadius, sSplitRadius); - } - - if (v.mSmallY <= h.y && h.y <= v.mBigY) - if (h.mSmallX < v.x && v.x < h.mBigX) - { - QPointF point(v.x, h.y); - mSplits.append(point); - mShape.addEllipse(point, sSplitRadius, sSplitRadius); - } - } + mSplits.append(point); + mShape.addEllipse(point, sSplitRadius, sSplitRadius); } qreal smallest_x = std::numeric_limits::max(); @@ -204,87 +191,4 @@ namespace hal mVLines.append(VLine{x, mSmallY, mBigY}); } - - void StandardGraphicsNet::Lines::mergeLines() - { - QVector merged_h_lines; - QVector merged_v_lines; - - for (const HLine& h : mHLines) - { - QVector overlaps; - - for (int i = 0; i < merged_h_lines.size(); ++i) - if (h.y == merged_h_lines.at(i).y) - { - if (h.mBigX < merged_h_lines.at(i).mSmallX || merged_h_lines.at(i).mBigX < h.mSmallX) - continue; - - overlaps.append(i); - } - - if (overlaps.isEmpty()) - merged_h_lines.append(h); - else - { - qreal smallest_x = h.mSmallX; - qreal biggest_x = h.mBigX; - - for (int i = 0; i < overlaps.size(); ++i) - { - int index = overlaps.at(i) - i; - - if (merged_h_lines.at(index).mSmallX < smallest_x) - smallest_x = merged_h_lines.at(index).mSmallX; - - if (merged_h_lines.at(index).mBigX > biggest_x) - biggest_x = merged_h_lines.at(index).mBigX; - - merged_h_lines.remove(index); - } - - merged_h_lines.append(HLine{smallest_x, biggest_x, h.y}); - } - } - - for (const VLine& v : mVLines) - { - QVector overlaps; - - for (int i = 0; i < merged_v_lines.size(); ++i) - if (v.x == merged_v_lines.at(i).x) - { - if (v.mBigY < merged_v_lines.at(i).mSmallY || merged_v_lines.at(i).mBigY < v.mSmallY) - continue; - - overlaps.append(i); - } - - if (overlaps.isEmpty()) - merged_v_lines.append(v); - else - { - qreal smallest_y = v.mSmallY; - qreal biggest_y = v.mBigY; - - for (int i = 0; i < overlaps.size(); ++i) - { - int index = overlaps.at(i) - i; - - if (merged_v_lines.at(index).mSmallY < smallest_y) - smallest_y = merged_v_lines.at(index).mSmallY; - - if (merged_v_lines.at(index).mBigY > biggest_y) - biggest_y = merged_v_lines.at(index).mBigY; - - merged_v_lines.remove(index); - } - - merged_v_lines.append(VLine{v.x, smallest_y, biggest_y}); - } - } - - mHLines = merged_h_lines; - mVLines = merged_v_lines; - } } // namespace hal diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index 15ef6ebee91..15e3c70f9f6 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -36,14 +36,13 @@ namespace hal } const static qreal sLaneSpacing = 10; - const static qreal sJunctionPadding = 10; const static qreal sHRoadPadding = 10; const static qreal sVRoadPadding = 10; const static qreal sMinimumVChannelWidth = 20; const static qreal sMinimumHChannelHeight = 20; GraphLayouter::GraphLayouter(GraphContext* context, QObject* parent) - : QObject(parent), mScene(new GraphicsScene(this)), mParentContext(context), mDone(false), mRollbackStatus(0), mOptimizeNetLayout(true) + : QObject(parent), mScene(new GraphicsScene(this)), mParentContext(context), mDone(false), mRollbackStatus(0), mDumpJunctions(true) { SelectionDetailsWidget* details = gContentManager->getSelectionDetailsWidget(); if (details) @@ -212,24 +211,35 @@ namespace hal return mYValues.last() + (inx - mYValues.size() - 1) * defaultGridHeight(); } - void GraphLayouter::alternateLayout() + void GraphLayouter::layout() { + QElapsedTimer timer; + timer.start(); + mParentContext->layoutProgress(0); + mScene->deleteAllItems(); + clearLayoutData(); + + createBoxes(); + mParentContext->layoutProgress(1); getWireHash(); mParentContext->layoutProgress(2); findMaxBoxDimensions(); mParentContext->layoutProgress(3); - alternateMaxChannelLanes(); + findMaxChannelLanes(); mParentContext->layoutProgress(4); calculateJunctionMinDistance(); mParentContext->layoutProgress(5); - alternateGateOffsets(); + calculateGateOffsets(); mParentContext->layoutProgress(6); - alternatePlaceGates(); + + mCoordArrayX = new SceneCoordinateArray(mCoordX); + mCoordArrayY = new SceneCoordinateArray(mCoordY); + + placeGates(); mParentContext->layoutProgress(7); - mDone = true; - alternateDrawNets(); + drawNets(); drawComments(); updateSceneRect(); @@ -240,42 +250,12 @@ namespace hal mScene->debugSetLayouterGrid(xValues(), yValues(), defaultGridHeight(), defaultGridWidth()); #endif mRollbackStatus = 0; - } - void GraphLayouter::layout() - { - QElapsedTimer timer; - timer.start(); - mParentContext->layoutProgress(0); - mScene->deleteAllItems(); - clearLayoutData(); + qDebug() << "elapsed time (experimental new) layout [ms]" << timer.elapsed(); - createBoxes(); - if (mOptimizeNetLayout) - { - alternateLayout(); - qDebug() << "elapsed time (experimental new) layout [ms]" << timer.elapsed(); - return; - } - calculateNets(); - findMaxBoxDimensions(); - findMaxChannelLanes(); - resetRoadsAndJunctions(); - calculateMaxChannelDimensions(); - calculateGateOffsets(); - placeGates(); + delete mCoordArrayX; + delete mCoordArrayY; mDone = true; - drawNets(); - updateSceneRect(); - - mScene->moveNetsToBackground(); - mScene->handleExternSelectionChanged(nullptr); - -#ifdef GUI_DEBUG_GRID - mScene->debugSetLayouterGrid(xValues(), yValues(), defaultGridHeight(), defaultGridWidth()); -#endif - mRollbackStatus = 0; - qDebug() << "elapsed time (classic) layout [ms]" << timer.elapsed(); } void GraphLayouter::prepareRollback() @@ -319,41 +299,12 @@ namespace hal mBoxes.clearBoxes(); clearComments(); - for (const GraphLayouter::Road* r : mHRoads.values()) - delete r; - mHRoads.clear(); - - for (const GraphLayouter::Road* r : mVRoads.values()) - delete r; - mVRoads.clear(); - - for (const GraphLayouter::Junction* j : mJunctions.values()) - delete j; - mJunctions.clear(); - mMaxNodeWidthForX.clear(); mMaxNodeHeightForY.clear(); - mMaxVChannelLanesForX.clear(); - mMaxHChannelLanesForY.clear(); - - mMaxVChannelLeftSpacingForX.clear(); - mMaxVChannelRightSpacingForX.clear(); - mMaxHChannelTopSpacingForY.clear(); - mMaxHChannelBottomSpacingForY.clear(); - - mMaxVChannelWidthForX.clear(); - mMaxHChannelHeightForY.clear(); - mNodeOffsetForX.clear(); mNodeOffsetForY.clear(); - mMaxLeftJunctionSpacingForX.clear(); - mMaxRightJunctionSpacingForX.clear(); - - mMaxTopJunctionSpacingForY.clear(); - mMaxBottomJunctionSpacingForY.clear(); - mMaxLeftIoPaddingForChannelX.clear(); mMaxRightIoPaddingForChannelX.clear(); @@ -384,6 +335,8 @@ namespace hal mNodeBoundingBox = QRect(); mViewInput.clear(); mViewOutput.clear(); + + mLaneMap.clear(); } void GraphLayouter::createBoxes() @@ -593,7 +546,7 @@ namespace hal // iend == 0 => horizontal wire: right endpoint junction: left entry NetLayoutPoint pnt = iend ? it.key().endPoint(NetLayoutWire::SourcePoint) : it.key().endPoint(NetLayoutWire::DestinationPoint); int idirBase = it.key().isHorizontal() ? NetLayoutDirection::Left : NetLayoutDirection::Up; - mJunctionEntries[pnt].setEntries(idirBase + iend, it.value()); + mJunctionEntries[pnt].mEntries[idirBase + iend] = it.value(); } } @@ -602,10 +555,10 @@ namespace hal { NetLayoutPoint inPnt(nbox->x(), nbox->y() * 2); QList inpNets = nbox->item()->inputNets(); - mJunctionEntries[inPnt].setEntries(NetLayoutDirection::Right, nbox->item()->inputNets()); + mJunctionEntries[inPnt].mEntries[NetLayoutDirection::Right] = nbox->item()->inputNets(); mEndpointHash[inPnt].setInputPins(nbox->item()->inputNets(), nbox->item()->yTopPinDistance(), nbox->item()->yEndpointDistance()); NetLayoutPoint outPnt(nbox->x() + 1, nbox->y() * 2); - mJunctionEntries[outPnt].setEntries(NetLayoutDirection::Left, nbox->item()->outputNets()); + mJunctionEntries[outPnt].mEntries[NetLayoutDirection::Left] = nbox->item()->outputNets(); mEndpointHash[outPnt].setOutputPins(nbox->item()->outputNets(), nbox->item()->yTopPinDistance(), nbox->item()->yEndpointDistance()); } @@ -614,7 +567,7 @@ namespace hal QList netIds; netIds.append(itGlInp.key()); NetLayoutPoint pnt(mNodeBoundingBox.left(), 2 * itGlInp.value()); - mJunctionEntries[pnt].setEntries(NetLayoutDirection::Left, netIds); + mJunctionEntries[pnt].mEntries[NetLayoutDirection::Left] = netIds; if (!mEndpointHash.contains(pnt)) mEndpointHash[pnt].setOutputPins(netIds, 0, 0); } @@ -624,293 +577,25 @@ namespace hal QList netIds; netIds.append(itGlOut.key()); NetLayoutPoint pnt(mNodeBoundingBox.right() + 1, 2 * itGlOut.value()); - mJunctionEntries[pnt].setEntries(NetLayoutDirection::Right, netIds); + mJunctionEntries[pnt].mEntries[NetLayoutDirection::Right] = netIds; if (!mEndpointHash.contains(pnt)) mEndpointHash[pnt].setInputPins(netIds, 0, 0); } - for (auto it = mJunctionEntries.constBegin(); it != mJunctionEntries.constEnd(); ++it) - { - // it.value().dumpFile(it.key()); - // qDebug() << "Junction at" << it.key().x() << it.key().y(); - NetLayoutJunction* nlj = new NetLayoutJunction(it.value()); - if (nlj->lastError() != NetLayoutJunction::Ok) - qDebug() << "Junction route error" << nlj->lastError() << it.key(); - mJunctionHash.insert(it.key(), nlj); - } - } - - void GraphLayouter::calculateNets() - { - for (const u32 id : mParentContext->nets()) + auto it = mJunctionEntries.constBegin(); + while (it != mJunctionEntries.constEnd() || !mJunctionThreads.isEmpty()) { - Net* n = gNetlist->get_net_by_id(id); - assert(n); - - if (n->is_unrouted()) - continue; - - UsedPaths used; - - for (Endpoint* src : n->get_sources()) + if (it != mJunctionEntries.constEnd() && mJunctionThreads.size() < QThread::idealThreadCount()) { - // FIND SRC BOX - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (node.isNull()) - continue; - - NodeBox* src_box = mBoxes.boxForNode(node); - assert(src_box); - - // FOR EVERY DST - for (Endpoint* dst : n->get_destinations()) - { - // FIND DST BOX - node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - if (node.isNull()) - continue; - - NodeBox* dst_box = mBoxes.boxForNode(node); - assert(dst_box); - - // ROAD BASED DISTANCE (x_distance - 1) - const int x_distance = dst_box->x() - src_box->x() - 1; - const int y_distance = dst_box->y() - src_box->y(); - - if (!y_distance && vRoadJumpPossible(src_box->x() + 1, dst_box->x(), src_box->y())) - { - // SPECIAL CASE INDIRECT HORIZONTAL NEIGHBORS - Road* dst_v_road = getVRoad(dst_box->x(), dst_box->y()); - used.mVRoads.insert(dst_v_road); - continue; - } - - Road* src_v_road = getVRoad(src_box->x() + 1, src_box->y()); - - if (!(x_distance || y_distance)) - { - // SPECIAL CASE DIRECT HORIZONTAL NEIGHBORS - used.mVRoads.insert(src_v_road); - continue; - } - - // NORMAL CASE - // CONNECT SRC TO V ROAD, TRAVEL X DISTANCE, TRAVEL Y DISTANCE, CONNECT V ROAD TO DST - used.mVRoads.insert(src_v_road); - - Junction* initial_junction = nullptr; - int remaining_y_distance = y_distance; - - if (y_distance < 0) - { - // TRAVEL UP - initial_junction = getJunction(src_v_road->x, src_v_road->y); - - if (src_v_road->mLanes != initial_junction->mVLanes) - { - if (src_v_road->mLanes < initial_junction->mVLanes) - used.mCloseBottomJunctions.insert(initial_junction); - else - used.mFarBottomJunctions.insert(initial_junction); - } - } - else - { - // TRAVEL DOWN - initial_junction = getJunction(src_v_road->x, src_v_road->y + 1); - - if (src_v_road->mLanes != initial_junction->mVLanes) - { - if (src_v_road->mLanes < initial_junction->mVLanes) - used.mCloseTopJunctions.insert(initial_junction); - else - used.mFarTopJunctions.insert(initial_junction); - } - - if (!y_distance) - remaining_y_distance = -1; - } - - used.mVJunctions.insert(initial_junction); - - Junction* last_junction = initial_junction; - - if (x_distance) - { - used.mHJunctions.insert(initial_junction); - - int remaining_x_distance = x_distance; - - // TRAVEL REMAINING X DISTANCE - while (remaining_x_distance) - { - Road* r = nullptr; - Junction* j = nullptr; - - if (x_distance > 0) - { - // TRAVEL RIGHT - r = getHRoad(last_junction->x, last_junction->y); - - if (last_junction->mHLanes != r->mLanes) - { - if (last_junction->mHLanes < r->mLanes) - used.mFarRightJunctions.insert(last_junction); - else - used.mCloseRightJunctions.insert(last_junction); - } - - j = getJunction(last_junction->x + 1, last_junction->y); - - if (r->mLanes != j->mHLanes) - { - if (r->mLanes < j->mHLanes) - used.mCloseLeftJunctions.insert(j); - else - used.mFarLeftJunctions.insert(j); - } - - --remaining_x_distance; - } - else - { - // TRAVEL LEFT - r = getHRoad(last_junction->x - 1, last_junction->y); - - if (last_junction->mHLanes != r->mLanes) - { - if (last_junction->mHLanes < r->mLanes) - used.mFarLeftJunctions.insert(last_junction); - else - used.mCloseLeftJunctions.insert(last_junction); - } - - j = getJunction(last_junction->x - 1, last_junction->y); - - if (r->mLanes != j->mHLanes) - { - if (r->mLanes < j->mHLanes) - used.mCloseRightJunctions.insert(j); - else - used.mFarRightJunctions.insert(j); - } - - ++remaining_x_distance; - } - - used.mHRoads.insert(r); - used.mHJunctions.insert(j); - - last_junction = j; - } - - used.mVJunctions.insert(last_junction); - } - - // TRAVEL REMAINING Y DISTANCE - if (remaining_y_distance > 0) - { - while (remaining_y_distance != 1) - { - // TRAVEL DOWN - Road* r = getVRoad(last_junction->x, last_junction->y); - - if (last_junction->mVLanes != r->mLanes) - { - if (last_junction->mVLanes < r->mLanes) - used.mFarBottomJunctions.insert(last_junction); - else - used.mCloseBottomJunctions.insert(last_junction); - } - - Junction* j = getJunction(last_junction->x, last_junction->y + 1); - - if (r->mLanes != j->mVLanes) - { - if (r->mLanes < j->mVLanes) - used.mCloseTopJunctions.insert(j); - else - used.mFarTopJunctions.insert(j); - } - - used.mVRoads.insert(r); - used.mVJunctions.insert(j); - - last_junction = j; - - --remaining_y_distance; - } - } - else - { - while (remaining_y_distance != -1) - { - // TRAVEL UP - Road* r = getVRoad(last_junction->x, last_junction->y - 1); - - if (last_junction->mVLanes != r->mLanes) - { - if (last_junction->mVLanes < r->mLanes) - used.mFarTopJunctions.insert(last_junction); - else - used.mCloseTopJunctions.insert(last_junction); - } - - Junction* j = getJunction(last_junction->x, last_junction->y - 1); - - if (r->mLanes != j->mVLanes) - { - if (r->mLanes < j->mVLanes) - used.mCloseBottomJunctions.insert(j); - else - used.mFarBottomJunctions.insert(j); - } - - used.mVRoads.insert(r); - used.mVJunctions.insert(j); - - last_junction = j; - - ++remaining_y_distance; - } - } - - Road* dst_road = nullptr; - - if (y_distance > 0) - { - // TRAVEL DOWN - dst_road = getVRoad(last_junction->x, last_junction->y); - - if (last_junction->mVLanes != dst_road->mLanes) - { - if (last_junction->mVLanes < dst_road->mLanes) - used.mFarBottomJunctions.insert(last_junction); - else - used.mCloseBottomJunctions.insert(last_junction); - } - } - else - { - // TRAVEL UP - dst_road = getVRoad(last_junction->x, last_junction->y - 1); - - if (last_junction->mVLanes != dst_road->mLanes) - { - if (last_junction->mVLanes < dst_road->mLanes) - used.mFarTopJunctions.insert(last_junction); - else - used.mCloseTopJunctions.insert(last_junction); - } - } - - used.mVJunctions.insert(last_junction); - used.mVRoads.insert(dst_road); - } + if (mDumpJunctions) + it.value().dumpToFile(it.key()); + JunctionThread* jt = new JunctionThread(it.key(), it.value()); + connect(jt,&QThread::finished,this,&GraphLayouter::handleJunctionThreadFinished); + mJunctionThreads.append(jt); + jt->start(); + ++it; } - - commitUsedPaths(used); + qApp->processEvents(); } } @@ -942,7 +627,7 @@ namespace hal } } - void GraphLayouter::alternateMaxChannelLanes() + void GraphLayouter::findMaxChannelLanes() { // maximum parallel wires for atomic network for (auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it) @@ -989,123 +674,6 @@ namespace hal } } - void GraphLayouter::findMaxChannelLanes() - { - for (const Road* r : mVRoads.values()) - storeMax(mMaxVChannelLanesForX, r->x, r->mLanes); - - for (const Road* r : mHRoads.values()) - storeMax(mMaxHChannelLanesForY, r->y, r->mLanes); - - for (const Junction* j : mJunctions.values()) - { - storeMax(mMaxVChannelLanesForX, j->x, j->mVLanes); - storeMax(mMaxHChannelLanesForY, j->y, j->mHLanes); - } - } - - void GraphLayouter::resetRoadsAndJunctions() - { - for (Road* r : mHRoads.values()) - r->mLanes = 0; - - for (Road* r : mVRoads.values()) - r->mLanes = 0; - - for (Junction* j : mJunctions.values()) - { - // LEFT - unsigned int combined_lane_changes = j->mCloseLeftLaneChanges + j->mFarLeftLaneChanges; - qreal spacing = 0; - - if (combined_lane_changes) - spacing = (combined_lane_changes - 1) * sLaneSpacing + sJunctionPadding; - - storeMax(mMaxLeftJunctionSpacingForX, j->x, spacing); - - // RIGHT - combined_lane_changes = j->mCloseRightLaneChanges + j->mFarRightLaneChanges; - spacing = 0; - - if (combined_lane_changes) - spacing = (combined_lane_changes - 1) * sLaneSpacing + sJunctionPadding; - - storeMax(mMaxRightJunctionSpacingForX, j->x, spacing); - - // TOP - combined_lane_changes = j->mCloseTopLaneChanges + j->mFarTopLaneChanges; - spacing = 0; - - if (combined_lane_changes) - spacing = (combined_lane_changes - 1) * sLaneSpacing + sJunctionPadding; - - storeMax(mMaxTopJunctionSpacingForY, j->y, spacing); - - // BOTTOM - combined_lane_changes = j->mCloseBottomLaneChanges + j->mFarBottomLaneChanges; - spacing = 0; - - if (combined_lane_changes) - spacing = (combined_lane_changes - 1) * sLaneSpacing + sJunctionPadding; - - storeMax(mMaxBottomJunctionSpacingForY, j->y, spacing); - - j->mHLanes = 0; - j->mVLanes = 0; - - j->mCloseLeftLaneChanges = 0; - j->mCloseRightLaneChanges = 0; - j->mCloseTopLaneChanges = 0; - j->mCloseBottomLaneChanges = 0; - - j->mFarLeftLaneChanges = 0; - j->mFarRightLaneChanges = 0; - j->mFarTopLaneChanges = 0; - j->mFarBottomLaneChanges = 0; - } - } - - void GraphLayouter::calculateMaxChannelDimensions() - { - auto i = mMaxVChannelLanesForX.constBegin(); - while (i != mMaxVChannelLanesForX.constEnd()) - { - qreal left_spacing = std::max(sVRoadPadding + mMaxLeftIoPaddingForChannelX.value(i.key()), mMaxLeftJunctionSpacingForX.value(i.key())); - mMaxVChannelLeftSpacingForX.insert(i.key(), left_spacing); - - qreal right_spacing = std::max(sVRoadPadding + mMaxRightIoPaddingForChannelX.value(i.key()), mMaxRightJunctionSpacingForX.value(i.key())); - mMaxVChannelRightSpacingForX.insert(i.key(), right_spacing); - - qreal width = left_spacing + right_spacing; - - if (i.value()) - width += (i.value() - 1) * sLaneSpacing; - - mMaxVChannelWidthForX.insert(i.key(), std::max(width, sMinimumVChannelWidth)); - - ++i; - } - - i = mMaxHChannelLanesForY.constBegin(); - while (i != mMaxHChannelLanesForY.constEnd()) - { - qreal top_spacing = std::max(sHRoadPadding, mMaxTopJunctionSpacingForY.value(i.key())); - mMaxHChannelTopSpacingForY.insert(i.key(), top_spacing); - - qreal bottom_spacing = std::max(sHRoadPadding, mMaxBottomJunctionSpacingForY.value(i.key())); - mMaxHChannelBottomSpacingForY.insert(i.key(), bottom_spacing); - - qreal height = top_spacing + bottom_spacing; - - if (i.value()) - height += (i.value() - 1) * sLaneSpacing; - - mMaxHChannelHeightForY.insert(i.key(), std::max(height, sMinimumHChannelHeight)); - - ++i; - } - } - void GraphLayouter::calculateJunctionMinDistance() { for (auto itJun = mJunctionHash.constBegin(); itJun != mJunctionHash.constEnd(); ++itJun) @@ -1136,7 +704,7 @@ namespace hal } } - void GraphLayouter::alternateGateOffsets() + void GraphLayouter::calculateGateOffsets() { QHash xInputPadding; QHash xOutputPadding; @@ -1212,48 +780,7 @@ namespace hal } } - void GraphLayouter::calculateGateOffsets() - { - mNodeOffsetForX.insert(0, 0); - mNodeOffsetForY.insert(0, 0); - - mXValues.append(0); - mYValues.append(0); - - if (mMaxXIndex) - for (int i = 1; i <= mMaxXIndex; ++i) - { - qreal offset = mNodeOffsetForX.value(i - 1) + mMaxNodeWidthForX.value(i - 1) + std::max(mMaxVChannelWidthForX.value(i), sMinimumVChannelWidth); - mNodeOffsetForX.insert(i, offset); - mXValues.append(offset); - } - - if (mMinXIndex) - for (int i = -1; i >= mMinXIndex; --i) - { - qreal offset = mNodeOffsetForX.value(i + 1) - mMaxNodeWidthForX.value(i) - std::max(mMaxVChannelWidthForX.value(i + 1), sMinimumVChannelWidth); - mNodeOffsetForX.insert(i, offset); - mXValues.prepend(offset); - } - - if (mMaxYIndex) - for (int i = 1; i <= mMaxYIndex; ++i) - { - qreal offset = mNodeOffsetForY.value(i - 1) + mMaxNodeHeightForY.value(i - 1) + std::max(mMaxHChannelHeightForY.value(i), sMinimumHChannelHeight); - mNodeOffsetForY.insert(i, offset); - mYValues.append(offset); - } - - if (mMinYIndex) - for (int i = -1; i >= mMinYIndex; --i) - { - qreal offset = mNodeOffsetForY.value(i + 1) - mMaxNodeHeightForY.value(i) - std::max(mMaxHChannelHeightForY.value(i + 1), sMinimumHChannelHeight); - mNodeOffsetForY.insert(i, offset); - mYValues.prepend(offset); - } - } - - void GraphLayouter::alternatePlaceGates() + void GraphLayouter::placeGates() { for (const NodeBox* box : mBoxes) { @@ -1281,15 +808,6 @@ namespace hal } } - void GraphLayouter::placeGates() - { - for (NodeBox* box : mBoxes) - { - box->setItemPosition(mNodeOffsetForX.value(box->x()), mNodeOffsetForY.value(box->y())); - mScene->addGraphItem(box->item()); - } - } - void GraphLayouter::drawComments() { for (NodeBox* box : mBoxes) @@ -1305,32 +823,55 @@ namespace hal } } - void GraphLayouter::alternateDrawNets() + void GraphLayouter::drawNets() { // lane for given wire and net id - QHash> laneMap; for (auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it) { int ilane = 0; for (u32 id : it.value()) - laneMap[id].insert(it.key(), ilane++); + mLaneMap[id].insert(it.key(), ilane++); } int netCount = mParentContext->nets().size(); int percentCount = netCount / 93; int doneCount = 0; - for (const u32 id : mParentContext->nets()) + mNetsToDraw = mParentContext->nets(); + mNetIterator = mNetsToDraw.constBegin(); + + + + enum LoopState { LoopInit, CanStartThread, WaitForSlot, WaitForLastThread, LoopDone } loopState = LoopInit; + while (loopState != LoopDone) { - ++doneCount; - if (percentCount) + if (mNetIterator != mNetsToDraw.constEnd()) { - if (doneCount % percentCount == 0) - mParentContext->layoutProgress(7 + doneCount / percentCount); + if (mDrawNetThreads.size() < QThread::idealThreadCount()) + loopState = CanStartThread; + else + loopState = WaitForSlot; } else - mParentContext->layoutProgress(7 + (int)floor(92. * doneCount / netCount)); + { + if (mDrawNetThreads.isEmpty()) + loopState = LoopDone; + else + loopState = WaitForLastThread; + } + + if (loopState == LoopDone) + break; + + if (loopState == WaitForLastThread || loopState == WaitForSlot) + { + qApp->processEvents(); + continue; + } + + Q_ASSERT(loopState == CanStartThread); + u32 id = *(mNetIterator++); Net* n = gNetlist->get_net_by_id(id); if (!n) @@ -1342,10 +883,12 @@ namespace hal switch (epl.netType()) { case EndpointList::NoEndpoint: + ++doneCount; break; case EndpointList::SingleSource: case EndpointList::SingleDestination: case EndpointList::ConstantLevel: + ++doneCount; drawNetsIsolated(id, n, epl); break; ; @@ -1357,98 +900,77 @@ namespace hal if (!regularNet) continue; - StandardGraphicsNet::Lines lines; - - const QHash& wMap = laneMap.value(id); - for (auto it = wMap.constBegin(); it != wMap.constEnd(); ++it) + ++doneCount; + if (percentCount) { - NetLayoutPoint wFromPoint = it.key().endPoint(NetLayoutWire::SourcePoint); - NetLayoutPoint wToPoint = it.key().endPoint(NetLayoutWire::DestinationPoint); - NetLayoutJunction* j0 = mJunctionHash.value(wFromPoint); - NetLayoutJunction* j1 = mJunctionHash.value(wToPoint); - int ilane = it.value(); - int ix0 = wFromPoint.x(); - int iy0 = wFromPoint.y(); - int ix1 = wToPoint.x(); - int iy1 = wToPoint.y(); - - if (it.key().isHorizontal()) - { - float x0 = j0 ? mCoordX[ix0].lanePosition(j0->rect().right()) : mCoordX[ix0].junctionExit(); - float x1 = j1 ? mCoordX[ix1].lanePosition(j1->rect().left()) : mCoordX[ix1].junctionEntry(); - float yy = mCoordY[iy0].lanePosition(ilane); - lines.appendHLine(x0, x1, yy); - } - else - { - float y0, y1; - float xx = mCoordX[ix0].lanePosition(ilane); - if (wToPoint.isEndpoint()) - { - // netjunction -> endpoint - auto itEpc = mEndpointHash.find(wToPoint); - y0 = j0 ? mCoordY[iy0].lanePosition(j0->rect().bottom()) : mCoordY[iy0].junctionExit(); - y1 = itEpc != mEndpointHash.constEnd() ? itEpc.value().lanePosition(j1->rect().top(), true) : mCoordY[iy1].junctionEntry(); - // if (itEpc==mEndpointHash.constEnd()) - // qDebug() << "xxx to endp" << wToPoint.x() << wToPoint.y() << y0 << y1; - } - else - { - // endpoint -> netjunction - auto itEpc = mEndpointHash.find(wFromPoint); - y0 = itEpc != mEndpointHash.constEnd() ? itEpc.value().lanePosition(j0->rect().bottom(), true) : mCoordY[iy0].junctionExit(); - y1 = j1 ? mCoordY[iy1].lanePosition(j1->rect().top()) : mCoordY[iy1].junctionEntry(); - // if (itEpc==mEndpointHash.constEnd()) - // qDebug() << "xxx fr endp" << wFromPoint.x() << wFromPoint.y() << y0 << y1; - } - if (y1 > y0) - lines.appendVLine(xx, y0, y1); - } - } - drawNetsJunction(lines, id); - drawNetsEndpoint(lines, id); + if (doneCount % percentCount == 0) + mParentContext->layoutProgress(7 + doneCount / percentCount); + } + else + mParentContext->layoutProgress(7 + (int)floor(92. * doneCount / netCount)); - lines.mergeLines(); + DrawNetThread* dnt = new DrawNetThread(id,this); + connect(dnt,&QThread::finished,this,&GraphLayouter::handleDrawNetThreadFinished); + mDrawNetThreads.append(dnt); + dnt->start(); + } + } - GraphicsNet* graphicsNet = nullptr; - switch (epl.netType()) - { - case EndpointList::HasGlobalEndpoint: - if (epl.hasInputArrow()) - { - StandardArrowNet* san = new StandardArrowNet(n, lines); - graphicsNet = san; - int yGridPos = mGlobalInputHash.value(id, -1); - Q_ASSERT(yGridPos >= 0); - const EndpointCoordinate& epc = mEndpointHash.value(QPoint(mNodeBoundingBox.left(), yGridPos * 2)); - san->setInputPosition(QPointF(mCoordX.value(mNodeBoundingBox.left()).lanePosition(-1), epc.lanePosition(0, true))); - } - if (epl.hasOutputArrow()) - { - if (graphicsNet) mScene->addGraphItem(graphicsNet); - StandardArrowNet* san = new StandardArrowNet(n, lines); - graphicsNet = san; - int yGridPos = mGlobalOutputHash.value(id, -1); - Q_ASSERT(yGridPos >= 0); - QPoint pnt(mNodeBoundingBox.right() + 1, yGridPos * 2); - const EndpointCoordinate& epc = mEndpointHash.value(pnt); - const NetLayoutJunction* nlj = mJunctionHash.value(pnt); - Q_ASSERT(nlj); - san->setOutputPosition(QPointF(mCoordX.value(pnt.x()).lanePosition(nlj->rect().right() + 1), epc.lanePosition(0, true))); - } - break; - case EndpointList::SourceAndDestination: - if (lines.nLines() > 0) - graphicsNet = new StandardGraphicsNet(n, lines); - break; - default: - Q_ASSERT(0 > 1); // should never occur - break; - } + void GraphLayouter::handleJunctionThreadFinished() + { + JunctionThread* jt = static_cast(sender()); + mJunctionHash.insert(jt->mNetLayoutPoint,jt->mJunction); + mJunctionThreads.removeAll(jt); + jt->deleteLater(); + } + + void GraphLayouter::handleDrawNetThreadFinished() + { + DrawNetThread* dnt = static_cast(sender()); + Net* n = gNetlist->get_net_by_id(dnt->id()); + const EndpointList& epl = mWireEndpoint.value(dnt->id()); - if (graphicsNet) - mScene->addGraphItem(graphicsNet); + GraphicsNet* graphicsNet = nullptr; + switch (epl.netType()) + { + case EndpointList::HasGlobalEndpoint: + if (epl.hasInputArrow()) + { + StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines); + graphicsNet = san; + int yGridPos = mGlobalInputHash.value(dnt->id(), -1); + Q_ASSERT(yGridPos >= 0); + const EndpointCoordinate& epc = mEndpointHash.value(QPoint(mNodeBoundingBox.left(), yGridPos * 2)); + san->setInputPosition(QPointF(mCoordArrayX->lanePosition(mNodeBoundingBox.left(),-1), epc.lanePosition(0, true))); + } + if (epl.hasOutputArrow()) + { + if (graphicsNet) mScene->addGraphItem(graphicsNet); + StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines); + graphicsNet = san; + int yGridPos = mGlobalOutputHash.value(dnt->id(), -1); + Q_ASSERT(yGridPos >= 0); + QPoint pnt(mNodeBoundingBox.right() + 1, yGridPos * 2); + const EndpointCoordinate& epc = mEndpointHash.value(pnt); + const NetLayoutJunction* nlj = mJunctionHash.value(pnt); + Q_ASSERT(nlj); + san->setOutputPosition(QPointF(mCoordArrayX->lanePosition(pnt.x(),nlj->rect().right() + 1), epc.lanePosition(0, true))); + } + break; + case EndpointList::SourceAndDestination: + if (dnt->mLines.nLines() > 0) + graphicsNet = new StandardGraphicsNet(n, dnt->mLines, dnt->mKnots); + break; + default: + Q_ASSERT(0 > 1); // should never occur + break; } + + if (graphicsNet) + mScene->addGraphItem(graphicsNet); + + mDrawNetThreads.removeAll(dnt); + dnt->deleteLater(); } void GraphLayouter::drawNetsIsolated(u32 id, Net* n, const EndpointList& epl) @@ -1490,870 +1012,6 @@ namespace hal mScene->addGraphItem(net_item); } - void GraphLayouter::drawNetsEndpoint(StandardGraphicsNet::Lines& lines, u32 id) - { - for (auto it = mEndpointHash.constBegin(); it != mEndpointHash.constEnd(); ++it) - { - const EndpointCoordinate& epc = it.value(); - - QList inputsById = epc.inputPinIndex(id); - QList outputsById = epc.outputPinIndex(id); - if (inputsById.isEmpty() && outputsById.isEmpty()) - continue; - - const NetLayoutJunction* nlj = mJunctionHash.value(it.key()); - const SceneCoordinate& xScenePos = mCoordX.value(it.key().x()); - float xjLeft = xScenePos.lanePosition(nlj->rect().left()); - float xjRight = xScenePos.lanePosition(nlj->rect().right()); - Q_ASSERT(nlj); - - for (int inpInx : inputsById) - { - if (xjRight >= epc.xInput()) - { - // don't complain if "input" is in fact global output pin - auto ityOut = mGlobalOutputHash.find(id); - if (ityOut == mGlobalOutputHash.constEnd() || QPoint(mNodeBoundingBox.right() + 1, 2 * ityOut.value()) != it.key()) - qDebug() << "cannot connect input pin" << id << it.key().x() << it.key().y() / 2 << xjRight << epc.xInput(); - } - else - lines.appendHLine(xjRight, epc.xInput(), epc.lanePosition(inpInx, true)); - } - for (int outInx : outputsById) - { - if (epc.xOutput() >= xjLeft) - qDebug() << "cannot connect output pin" << id << it.key().x() << it.key().y() / 2 << xjLeft << epc.xOutput(); - else - lines.appendHLine(epc.xOutput(), xjLeft, epc.lanePosition(outInx, true)); - } - } - } - - void GraphLayouter::drawNetsJunction(StandardGraphicsNet::Lines& lines, u32 id) - { - for (auto jt = mJunctionHash.constBegin(); jt != mJunctionHash.constEnd(); ++jt) - { - auto epcIt = mEndpointHash.find(jt.key()); - int x = jt.key().x(); - int y = jt.key().y(); - bool isEndpoint = (y % 2 == 0); - - for (const NetLayoutJunctionWire& jw : jt.value()->netById(id).mWires) - { - if (jw.mHorizontal == 0) - { - Q_ASSERT(epcIt != mEndpointHash.constEnd() || !isEndpoint); - float x0 = mCoordX.value(x).lanePosition(jw.mFirst); - float x1 = mCoordX.value(x).lanePosition(jw.mLast); - float yy = isEndpoint ? epcIt.value().lanePosition(jw.mRoad, true) : mCoordY.value(y).lanePosition(jw.mRoad); - lines.appendHLine(x0, x1, yy); - } - else - { - float y0, y1; - if (!isEndpoint) - { - y0 = mCoordY.value(y).lanePosition(jw.mFirst); - y1 = mCoordY.value(y).lanePosition(jw.mLast); - } - else if (epcIt != mEndpointHash.constEnd()) - { - y0 = epcIt.value().lanePosition(jw.mFirst, true); - y1 = epcIt.value().lanePosition(jw.mLast, true); - } - else - { - y0 = mCoordY.value(y).junctionEntry(); - y1 = mCoordY.value(y).junctionExit(); - if (y1 <= y0) - y1 = y0 + 1; - } - float xx = mCoordX.value(x).lanePosition(jw.mRoad); - lines.appendVLine(xx, y0, y1); - } - } - } - } - - void GraphLayouter::drawNets() - { - // ROADS AND JUNCTIONS FILLED LEFT TO RIGHT, TOP TO BOTTOM - for (const u32 id : mParentContext->nets()) - { - Net* n = gNetlist->get_net_by_id(id); - assert(n); - - QSet outputAssigned; - - if (n->is_unrouted()) - { - // HANDLE GLOBAL NETS - ArrowSeparatedNet* net_item = new ArrowSeparatedNet(n); - - for (Endpoint* src : n->get_sources()) - { - if (src->get_gate()) - { - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb && !outputAssigned.contains(nb)) - { - net_item->addOutput(nb->item()->getOutputScenePosition(n->get_id(), QString::fromStdString(src->get_pin()->get_name()))); - outputAssigned.insert(nb); - } - } - } - - QSet inputAssigned; - - for (Endpoint* dst : n->get_destinations()) - { - if (dst->get_gate()) - { - Node node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb && !inputAssigned.contains(nb)) - { - net_item->addInput(nb->item()->getInputScenePosition(n->get_id(), QString::fromStdString(dst->get_pin()->get_name()))); - inputAssigned.insert(nb); - } - } - } - - net_item->finalize(); - mScene->addGraphItem(net_item); - continue; - } - - bool use_label = isConstNet(n); - - if (use_label) - { - LabeledSeparatedNet* net_item = new LabeledSeparatedNet(n, QString::fromStdString(n->get_name())); - - for (Endpoint* src : n->get_sources()) - { - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (!node.isNull()) - { - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - net_item->addOutput(nb->item()->getOutputScenePosition(n->get_id(), QString::fromStdString(src->get_pin()->get_name()))); - } - } - - for (Endpoint* dst : n->get_destinations()) - { - Node node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - net_item->addInput(nb->item()->getInputScenePosition(n->get_id(), QString::fromStdString(dst->get_pin()->get_name()))); - } - - net_item->finalize(); - mScene->addGraphItem(net_item); - - continue; - } - - // incomplete_net: existing destination or source of net not visible - // bool incomplete_net = false; - - bool src_found = false; - bool dst_found = false; - - for (Endpoint* src : n->get_sources()) - { - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (!node.isNull()) - src_found = true; - // else incomplete_net = true; - } - - for (Endpoint* dst : n->get_destinations()) - { - Node node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - - if (!node.isNull()) - dst_found = true; - // else incomplete_net = true; - } - - if (src_found && !dst_found) - { - ArrowSeparatedNet* net_item = new ArrowSeparatedNet(n); - - for (Endpoint* src : n->get_sources()) - { - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - net_item->addOutput(nb->item()->getOutputScenePosition(n->get_id(), QString::fromStdString(src->get_pin()->get_name()))); - } - - net_item->finalize(); - mScene->addGraphItem(net_item); - - continue; - } - - if (!src_found && dst_found) - { - ArrowSeparatedNet* net_item = new ArrowSeparatedNet(n); - - for (Endpoint* dst : n->get_destinations()) - { - Node node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - net_item->addInput(nb->item()->getInputScenePosition(n->get_id(), QString::fromStdString(dst->get_pin()->get_name()))); - } - - net_item->finalize(); - mScene->addGraphItem(net_item); - - continue; - } - - // HANDLE NORMAL NETS - UsedPaths used; - StandardGraphicsNet::Lines lines; - - // FOR EVERY SRC - for (Endpoint* src : n->get_sources()) - { - // FIND SRC BOX - const NodeBox* src_box = nullptr; - { - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - src_box = nb; - } - assert(src_box); - - const QPointF src_pin_position = src_box->item()->getOutputScenePosition(n->get_id(), QString::fromStdString(src->get_pin()->get_name())); - - // FOR EVERY DST - for (Endpoint* dst : n->get_destinations()) - { - // FIND DST BOX - const NodeBox* dst_box = nullptr; - - Node node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - dst_box = nb; - - assert(dst_box); - - // don't attempt to loop back a module output into its input - // (if this triggers, we found the net because it also has - // destinations outside the module) - if (src_box == dst_box && src_box->type() == Node::Module) - continue; - - QPointF dst_pin_position = dst_box->item()->getInputScenePosition(n->get_id(), QString::fromStdString(dst->get_pin()->get_name())); - - // ROAD BASED DISTANCE (x_distance - 1) - const int x_distance = dst_box->x() - src_box->x() - 1; - const int y_distance = dst_box->y() - src_box->y(); - - if (!y_distance && vRoadJumpPossible(src_box->x() + 1, dst_box->x(), src_box->y())) - { - // SPECIAL CASE INDIRECT HORIZONTAL NEIGHBORS - Road* dst_v_road = getVRoad(dst_box->x(), dst_box->y()); - - qreal x = sceneXForVChannelLane(dst_v_road->x, dst_v_road->mLanes); - - lines.appendHLine(src_pin_position.x(), x, src_pin_position.y()); - - if (src_pin_position.y() < dst_pin_position.y()) - lines.appendVLine(x, src_pin_position.y(), dst_pin_position.y()); - else if (src_pin_position.y() > dst_pin_position.y()) - lines.appendVLine(x, dst_pin_position.y(), src_pin_position.y()); - - lines.appendHLine(x, dst_pin_position.x(), dst_pin_position.y()); - - used.mVRoads.insert(dst_v_road); - continue; - } - - Road* src_v_road = getVRoad(src_box->x() + 1, src_box->y()); - - if (!(x_distance || y_distance)) - { - // SPECIAL CASE DIRECT HORIZONTAL NEIGHBORS - qreal x = sceneXForVChannelLane(src_v_road->x, src_v_road->mLanes); - - lines.appendHLine(src_pin_position.x(), x, src_pin_position.y()); - - if (src_pin_position.y() < dst_pin_position.y()) - lines.appendVLine(x, src_pin_position.y(), dst_pin_position.y()); - else if (src_pin_position.y() > dst_pin_position.y()) - lines.appendVLine(x, dst_pin_position.y(), src_pin_position.y()); - - lines.appendHLine(x, dst_pin_position.x(), dst_pin_position.y()); - - used.mVRoads.insert(src_v_road); - continue; - } - - // NORMAL CASE - // CONNECT SRC TO V ROAD, TRAVEL X DISTANCE, TRAVEL Y DISTANCE, CONNECT V ROAD TO DST - QPointF current_position(src_pin_position); - current_position.setX(sceneXForVChannelLane(src_v_road->x, src_v_road->mLanes)); - lines.appendHLine(src_pin_position.x(), current_position.x(), src_pin_position.y()); - used.mVRoads.insert(src_v_road); - - Junction* initial_junction = nullptr; - int remaining_y_distance = y_distance; - - if (y_distance < 0) - { - // TRAVEL UP - initial_junction = getJunction(src_v_road->x, src_v_road->y); - - if (src_v_road->mLanes != initial_junction->mVLanes) - { - // R -> J - if (src_v_road->mLanes < initial_junction->mVLanes) - { - // POS - qreal y = sceneYForCloseBottomLaneChange(initial_junction->y, initial_junction->mCloseBottomLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mCloseBottomJunctions.insert(initial_junction); - } - else - { - // NEG - qreal y = sceneYForFarBottomLaneChange(initial_junction->y, initial_junction->mFarBottomLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mFarBottomJunctions.insert(initial_junction); - } - - qreal x = sceneXForVChannelLane(initial_junction->x, initial_junction->mVLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - } - else - { - // TRAVEL DOWN - initial_junction = getJunction(src_v_road->x, src_v_road->y + 1); - - if (src_v_road->mLanes != initial_junction->mVLanes) - { - // R -> J - if (src_v_road->mLanes < initial_junction->mVLanes) - { - // POS - qreal y = sceneYForCloseTopLaneChange(initial_junction->y, initial_junction->mCloseTopLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mCloseTopJunctions.insert(initial_junction); - } - else - { - // NEG - qreal y = sceneYForFarTopLaneChange(initial_junction->y, initial_junction->mFarTopLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mFarTopJunctions.insert(initial_junction); - } - - qreal x = sceneXForVChannelLane(initial_junction->x, initial_junction->mVLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - - if (!y_distance) - remaining_y_distance = -1; - } - - used.mVJunctions.insert(initial_junction); - - Junction* last_junction = initial_junction; - - if (x_distance) - { - { - qreal y = sceneYForHChannelLane(initial_junction->y, initial_junction->mHLanes); - - if (current_position.y() < y) - lines.appendVLine(current_position.x(), current_position.y(), y); - else - lines.appendVLine(current_position.x(), y, current_position.y()); - - current_position.setY(y); - used.mHJunctions.insert(initial_junction); - } - - int remaining_x_distance = x_distance; - - // TRAVEL REMAINING X DISTANCE - while (remaining_x_distance) - { - Road* r = nullptr; - Junction* j = nullptr; - - if (x_distance > 0) - { - // TRAVEL RIGHT - r = getHRoad(last_junction->x, last_junction->y); - - if (last_junction->mHLanes != r->mLanes) - { - // J -> R - if (last_junction->mHLanes < r->mLanes) - { - // POS - qreal x = sceneXForFarRightLaneChange(last_junction->x, last_junction->mFarRightLaneChanges); - lines.appendHLine(current_position.x(), x, current_position.y()); - current_position.setX(x); - used.mFarRightJunctions.insert(last_junction); - } - else - { - // NEG - qreal x = sceneXForCloseRightLaneChange(last_junction->x, last_junction->mCloseRightLaneChanges); - lines.appendHLine(current_position.x(), x, current_position.y()); - current_position.setX(x); - used.mCloseRightJunctions.insert(last_junction); - } - - qreal y = sceneYForHChannelLane(r->y, r->mLanes); - - if (current_position.y() < y) - lines.appendVLine(current_position.x(), current_position.y(), y); - else - lines.appendVLine(current_position.x(), y, current_position.y()); - - current_position.setY(y); - } - - j = getJunction(last_junction->x + 1, last_junction->y); - - if (r->mLanes != j->mHLanes) - { - // R -> J - if (r->mLanes < j->mHLanes) - { - // POS - qreal x = sceneXForCloseLeftLaneChange(j->x, j->mCloseLeftLaneChanges); - lines.appendHLine(current_position.x(), x, current_position.y()); - current_position.setX(x); - used.mCloseLeftJunctions.insert(j); - } - else - { - // NEG - qreal x = sceneXForFarLeftLaneChange(j->x, j->mFarLeftLaneChanges); - lines.appendHLine(current_position.x(), x, current_position.y()); - current_position.setX(x); - used.mFarLeftJunctions.insert(j); - } - - qreal y = sceneYForHChannelLane(j->y, j->mHLanes); - - // DUPLICATE CODE ? - if (current_position.y() < y) - lines.appendVLine(current_position.x(), current_position.y(), y); - else - lines.appendVLine(current_position.x(), y, current_position.y()); - - current_position.setY(y); - } - - --remaining_x_distance; - } - else - { - // TRAVEL LEFT - r = getHRoad(last_junction->x - 1, last_junction->y); - - if (last_junction->mHLanes != r->mLanes) - { - // J -> R - if (last_junction->mHLanes < r->mLanes) - { - // POS - qreal x = sceneXForFarLeftLaneChange(last_junction->x, last_junction->mFarLeftLaneChanges); - lines.appendHLine(x, current_position.x(), current_position.y()); - current_position.setX(x); - used.mFarLeftJunctions.insert(last_junction); - } - else - { - // NEG - qreal x = sceneXForCloseLeftLaneChange(last_junction->x, last_junction->mCloseLeftLaneChanges); - lines.appendHLine(x, current_position.x(), current_position.y()); - current_position.setX(x); - used.mCloseLeftJunctions.insert(last_junction); - } - - qreal y = sceneYForHChannelLane(r->y, r->mLanes); - - // DUPLICATE CODE ? - if (current_position.y() < y) - lines.appendVLine(current_position.x(), current_position.y(), y); - else - lines.appendVLine(current_position.x(), y, current_position.y()); - - current_position.setY(y); - } - - j = getJunction(last_junction->x - 1, last_junction->y); - - if (r->mLanes != j->mHLanes) - { - // R -> J - if (r->mLanes < j->mHLanes) - { - // POS - qreal x = sceneXForCloseRightLaneChange(j->x, j->mCloseRightLaneChanges); - lines.appendHLine(x, current_position.x(), current_position.y()); - current_position.setX(x); - used.mCloseRightJunctions.insert(j); - } - else - { - // NEG - qreal x = sceneXForFarRightLaneChange(j->x, j->mFarRightLaneChanges); - lines.appendHLine(x, current_position.x(), current_position.y()); - current_position.setX(x); - used.mFarRightJunctions.insert(j); - } - - qreal y = sceneYForHChannelLane(j->y, j->mHLanes); - - // DUPLICATE CODE ? - if (current_position.y() < y) - lines.appendVLine(current_position.x(), current_position.y(), y); - else - lines.appendVLine(current_position.x(), y, current_position.y()); - - current_position.setY(y); - } - - ++remaining_x_distance; - } - - used.mHRoads.insert(r); - used.mHJunctions.insert(j); - - last_junction = j; - } - - qreal x = sceneXForVChannelLane(last_junction->x, last_junction->mVLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - used.mVJunctions.insert(last_junction); - } - - // TRAVEL REMAINING Y DISTANCE - if (remaining_y_distance > 0) - { - while (remaining_y_distance != 1) - { - // TRAVEL DOWN - Road* r = getVRoad(last_junction->x, last_junction->y); - - if (last_junction->mVLanes != r->mLanes) - { - // J -> R - if (last_junction->mVLanes < r->mLanes) - { - // POS - qreal y = sceneYForFarBottomLaneChange(last_junction->y, last_junction->mFarBottomLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mFarBottomJunctions.insert(last_junction); - } - else - { - // NEG - qreal y = sceneYForCloseBottomLaneChange(last_junction->y, last_junction->mCloseBottomLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mCloseBottomJunctions.insert(last_junction); - } - - qreal x = sceneXForVChannelLane(r->x, r->mLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - - Junction* j = getJunction(last_junction->x, last_junction->y + 1); - - if (r->mLanes != j->mVLanes) - { - // R -> J - if (r->mLanes < j->mVLanes) - { - // POS - qreal y = sceneYForCloseTopLaneChange(j->y, j->mCloseTopLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mCloseTopJunctions.insert(j); - } - else - { - // NEG - qreal y = sceneYForFarTopLaneChange(j->y, j->mFarTopLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mFarTopJunctions.insert(j); - } - - qreal x = sceneXForVChannelLane(j->x, j->mVLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - - used.mVRoads.insert(r); - used.mVJunctions.insert(j); - - last_junction = j; - - --remaining_y_distance; - } - } - else - { - while (remaining_y_distance != -1) - { - // TRAVEL UP - Road* r = getVRoad(last_junction->x, last_junction->y - 1); - - if (last_junction->mVLanes != r->mLanes) - { - // J -> R - if (last_junction->mVLanes < r->mLanes) - { - // POS - qreal y = sceneYForFarTopLaneChange(last_junction->y, last_junction->mFarTopLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mFarTopJunctions.insert(last_junction); - } - else - { - // NEG - qreal y = sceneYForCloseTopLaneChange(last_junction->y, last_junction->mCloseTopLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mCloseTopJunctions.insert(last_junction); - } - - qreal x = sceneXForVChannelLane(r->x, r->mLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - - Junction* j = getJunction(last_junction->x, last_junction->y - 1); - - if (r->mLanes != j->mVLanes) - { - // R -> J - if (r->mLanes < j->mVLanes) - { - // POS - qreal y = sceneYForCloseBottomLaneChange(j->y, j->mCloseBottomLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mCloseBottomJunctions.insert(j); - } - else - { - // NEG - qreal y = sceneYForFarBottomLaneChange(j->y, j->mFarBottomLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mFarBottomJunctions.insert(j); - } - - qreal x = sceneXForVChannelLane(j->x, j->mVLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - - used.mVRoads.insert(r); - used.mVJunctions.insert(j); - - last_junction = j; - - ++remaining_y_distance; - } - } - - Road* dst_road = nullptr; - - if (y_distance > 0) - { - // TRAVEL DOWN - dst_road = getVRoad(last_junction->x, last_junction->y); - - if (last_junction->mVLanes != dst_road->mLanes) - { - // J -> R - if (last_junction->mVLanes < dst_road->mLanes) - { - // POS - qreal y = sceneYForFarBottomLaneChange(last_junction->y, last_junction->mFarBottomLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mFarBottomJunctions.insert(last_junction); - } - else - { - // NEG - qreal y = sceneYForCloseBottomLaneChange(last_junction->y, last_junction->mCloseBottomLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mCloseBottomJunctions.insert(last_junction); - } - - qreal x = sceneXForVChannelLane(dst_road->x, dst_road->mLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - } - else - { - // TRAVEL UP - dst_road = getVRoad(last_junction->x, last_junction->y - 1); - - if (last_junction->mVLanes != dst_road->mLanes) - { - // J -> R - if (last_junction->mVLanes < dst_road->mLanes) - { - // POS - qreal y = sceneYForFarTopLaneChange(last_junction->y, last_junction->mFarTopLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mFarTopJunctions.insert(last_junction); - } - else - { - // NEG - qreal y = sceneYForCloseTopLaneChange(last_junction->y, last_junction->mCloseTopLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mCloseTopJunctions.insert(last_junction); - } - - qreal x = sceneXForVChannelLane(dst_road->x, dst_road->mLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - } - - used.mVJunctions.insert(last_junction); - - if (current_position.y() < dst_pin_position.y()) - lines.appendVLine(current_position.x(), current_position.y(), dst_pin_position.y()); - else - lines.appendVLine(current_position.x(), dst_pin_position.y(), current_position.y()); - - current_position.setY(dst_pin_position.y()); - - used.mVRoads.insert(dst_road); - - lines.appendHLine(current_position.x(), dst_pin_position.x(), current_position.y()); - - current_position = src_pin_position; - } - } - - lines.mergeLines(); - if (lines.nLines() > 0) - { - StandardGraphicsNet* GraphicsNet = new StandardGraphicsNet(n, lines); - mScene->addGraphItem(GraphicsNet); - } - commitUsedPaths(used); - } - } - void GraphLayouter::updateSceneRect() { // SCENE RECT STUFF BEHAVES WEIRDLY, FURTHER RESEARCH REQUIRED @@ -2437,44 +1095,6 @@ namespace hal return vRoadJumpPossible(r1->x, r2->x, r1->y); } - GraphLayouter::Road* GraphLayouter::getHRoad(const int x, const int y) - { - QPoint p(x, y); - auto it = mHRoads.find(p); - if (it != mHRoads.end()) - return it.value(); - - GraphLayouter::Road* r = new Road(x, y); - mHRoads.insert(p, r); - return r; - } - - GraphLayouter::Road* GraphLayouter::getVRoad(const int x, const int y) - { - QPoint p(x, y); - auto it = mVRoads.find(p); - if (it != mVRoads.end()) - return it.value(); - - GraphLayouter::Road* r = new Road(x, y); - mVRoads.insert(p, r); - return r; - } - - GraphLayouter::Junction* GraphLayouter::getJunction(const int x, const int y) - { - QPoint p(x, y); - auto it = mJunctions.find(p); - if (it != mJunctions.end()) - { - return it.value(); - } - - GraphLayouter::Junction* j = new Junction(x, y); - mJunctions.insert(p, j); - return j; - } - qreal GraphLayouter::hRoadHeight(const unsigned int mLanes) const { // LANES COUNTED FROM 1 @@ -2497,223 +1117,6 @@ namespace hal return width; } - qreal GraphLayouter::sceneYForHChannelLane(const int y, const unsigned int lane) const - { - // LINES NUMBERED FROM 0 - assert(mNodeOffsetForY.contains(y) || mNodeOffsetForY.contains(y - 1)); - - const qreal offset = lane * sLaneSpacing; - - if (y == 0) - return mNodeOffsetForY.value(y) - mMaxHChannelHeightForY.value(y) + mMaxHChannelTopSpacingForY.value(y) + offset; - else - return mNodeOffsetForY.value(y - 1) + mMaxNodeHeightForY.value(y - 1) + mMaxHChannelTopSpacingForY.value(y) + offset; - } - - qreal GraphLayouter::sceneXForVChannelLane(const int x, const unsigned int lane) const - { - // LINES NUMBERED FROM 0 - assert(mNodeOffsetForX.contains(x) || mNodeOffsetForX.contains(x - 1)); - - const qreal offset = lane * sLaneSpacing; - - if (mNodeOffsetForX.contains(x)) - return mNodeOffsetForX.value(x) - mMaxVChannelWidthForX.value(x) + mMaxVChannelLeftSpacingForX.value(x) + offset; - else - return mNodeOffsetForX.value(x - 1) + mMaxNodeWidthForX.value(x - 1) + mMaxVChannelLeftSpacingForX.value(x) + offset; - } - - qreal GraphLayouter::sceneXForCloseLeftLaneChange(const int channel_x, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - assert(mNodeOffsetForX.contains(channel_x) || mNodeOffsetForX.contains(channel_x - 1)); - - if (mNodeOffsetForX.contains(channel_x)) - return mNodeOffsetForX.value(channel_x) - mMaxVChannelWidthForX.value(channel_x) + mMaxVChannelLeftSpacingForX.value(channel_x) - sJunctionPadding - lane_change * sLaneSpacing; - else - return mNodeOffsetForX.value(channel_x - 1) + mMaxNodeWidthForX.value(channel_x - 1) + mMaxVChannelLeftSpacingForX.value(channel_x) - sJunctionPadding - lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneXForFarLeftLaneChange(const int channel_x, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - assert(mNodeOffsetForX.contains(channel_x) || mNodeOffsetForX.contains(channel_x - 1)); - - if (mNodeOffsetForX.contains(channel_x)) - return mNodeOffsetForX.value(channel_x) - mMaxVChannelWidthForX.value(channel_x) + mMaxVChannelLeftSpacingForX.value(channel_x) - mMaxLeftJunctionSpacingForX.value(channel_x) - + lane_change * sLaneSpacing; - else - return mNodeOffsetForX.value(channel_x - 1) + mMaxNodeWidthForX.value(channel_x - 1) + mMaxVChannelLeftSpacingForX.value(channel_x) - mMaxLeftJunctionSpacingForX.value(channel_x) - + lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneXForCloseRightLaneChange(const int channel_x, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - assert(mNodeOffsetForX.contains(channel_x) || mNodeOffsetForX.contains(channel_x - 1)); - - if (mNodeOffsetForX.contains(channel_x)) - return mNodeOffsetForX.value(channel_x) - mMaxVChannelRightSpacingForX.value(channel_x) + sJunctionPadding + lane_change * sLaneSpacing; - else - return mNodeOffsetForX.value(channel_x - 1) + mMaxNodeWidthForX.value(channel_x - 1) + mMaxVChannelWidthForX.value(channel_x) - mMaxVChannelRightSpacingForX.value(channel_x) - + sJunctionPadding + lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneXForFarRightLaneChange(const int channel_x, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - assert(mNodeOffsetForX.contains(channel_x) || mNodeOffsetForX.contains(channel_x - 1)); - - if (mNodeOffsetForX.contains(channel_x)) - return mNodeOffsetForX.value(channel_x) - mMaxVChannelRightSpacingForX.value(channel_x) + mMaxRightJunctionSpacingForX.value(channel_x) - lane_change * sLaneSpacing; - else - return mNodeOffsetForX.value(channel_x - 1) + mMaxNodeWidthForX.value(channel_x - 1) + mMaxVChannelWidthForX.value(channel_x) - mMaxVChannelRightSpacingForX.value(channel_x) - + mMaxRightJunctionSpacingForX.value(channel_x) - lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneYForCloseTopLaneChange(const int channel_y, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - if (channel_y == 0) - return mNodeOffsetForY.value(channel_y) - mMaxHChannelHeightForY.value(channel_y) + mMaxHChannelTopSpacingForY.value(channel_y) - sJunctionPadding - lane_change * sLaneSpacing; - else - return mNodeOffsetForY.value(channel_y - 1) + mMaxNodeHeightForY.value(channel_y - 1) + mMaxHChannelTopSpacingForY.value(channel_y) - sJunctionPadding - lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneYForFarTopLaneChange(const int channel_y, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - if (channel_y == 0) - return mNodeOffsetForY.value(channel_y) - mMaxHChannelHeightForY.value(channel_y) + mMaxHChannelTopSpacingForY.value(channel_y) - mMaxTopJunctionSpacingForY.value(channel_y) - + lane_change * sLaneSpacing; - else - return mNodeOffsetForY.value(channel_y - 1) + mMaxNodeHeightForY.value(channel_y - 1) + mMaxHChannelTopSpacingForY.value(channel_y) - mMaxTopJunctionSpacingForY.value(channel_y) - + lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneYForCloseBottomLaneChange(const int channel_y, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - if (channel_y == 0) - return mNodeOffsetForY.value(channel_y) - mMaxHChannelBottomSpacingForY.value(channel_y) + sJunctionPadding + lane_change * sLaneSpacing; - else - return mNodeOffsetForY.value(channel_y - 1) + mMaxNodeHeightForY.value(channel_y - 1) + mMaxHChannelHeightForY.value(channel_y) - mMaxHChannelBottomSpacingForY.value(channel_y) - + sJunctionPadding + lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneYForFarBottomLaneChange(const int channel_y, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - if (channel_y == 0) - return mNodeOffsetForY.value(channel_y) - mMaxHChannelBottomSpacingForY.value(channel_y) + mMaxBottomJunctionSpacingForY.value(channel_y) - lane_change * sLaneSpacing; - else - return mNodeOffsetForY.value(channel_y - 1) + mMaxNodeHeightForY.value(channel_y - 1) + mMaxHChannelHeightForY.value(channel_y) - mMaxHChannelBottomSpacingForY.value(channel_y) - + mMaxBottomJunctionSpacingForY.value(channel_y) - lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneXForCloseLeftLaneChange(const Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneXForCloseLeftLaneChange(j->x, j->mCloseLeftLaneChanges); - } - - qreal GraphLayouter::sceneXForFarLeftLaneChange(const GraphLayouter::Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneXForFarLeftLaneChange(j->x, j->mFarLeftLaneChanges); - } - - qreal GraphLayouter::sceneXForCloseRightLaneChange(const Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneXForCloseRightLaneChange(j->x, j->mCloseRightLaneChanges); - } - - qreal GraphLayouter::sceneXForFarRightLaneChange(const GraphLayouter::Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneXForFarRightLaneChange(j->x, j->mFarRightLaneChanges); - } - - qreal GraphLayouter::sceneYForCloseTopLaneChange(const Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneYForCloseTopLaneChange(j->y, j->mCloseTopLaneChanges); - } - - qreal GraphLayouter::sceneYForFarTopLaneChange(const GraphLayouter::Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneYForFarTopLaneChange(j->y, j->mFarTopLaneChanges); - } - - qreal GraphLayouter::sceneYForCloseBottomLaneChange(const Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneYForCloseBottomLaneChange(j->y, j->mCloseBottomLaneChanges); - } - - qreal GraphLayouter::sceneYForFarBottomLaneChange(const GraphLayouter::Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneYForFarBottomLaneChange(j->y, j->mFarBottomLaneChanges); - } - - void GraphLayouter::commitUsedPaths(const UsedPaths& used) - { - for (Road* r : used.mHRoads) - r->mLanes += 1; - - for (Road* r : used.mVRoads) - r->mLanes += 1; - - for (Junction* j : used.mHJunctions) - j->mHLanes += 1; - - for (Junction* j : used.mVJunctions) - j->mVLanes += 1; - - for (Junction* j : used.mCloseLeftJunctions) - j->mCloseLeftLaneChanges += 1; - - for (Junction* j : used.mCloseRightJunctions) - j->mCloseRightLaneChanges += 1; - - for (Junction* j : used.mCloseTopJunctions) - j->mCloseTopLaneChanges += 1; - - for (Junction* j : used.mCloseBottomJunctions) - j->mCloseBottomLaneChanges += 1; - - for (Junction* j : used.mFarLeftJunctions) - j->mFarLeftLaneChanges += 1; - - for (Junction* j : used.mFarRightJunctions) - j->mFarRightLaneChanges += 1; - - for (Junction* j : used.mFarTopJunctions) - j->mFarTopLaneChanges += 1; - - for (Junction* j : used.mFarBottomJunctions) - j->mFarBottomLaneChanges += 1; - } - void GraphLayouter::SceneCoordinate::testMinMax(int ilane) { if (ilane < minLane) @@ -2759,6 +1162,31 @@ namespace hal return junctionExit() + sHRoadPadding + mPadding; } + GraphLayouter::SceneCoordinateArray::SceneCoordinateArray(const QMap& inputMap) + : mArray(nullptr), mFirstIndex(0) + { + if (!inputMap.isEmpty()) + { + mArray = new float[inputMap.size()]; + auto it = inputMap.constBegin(); + mFirstIndex = it.key(); + for (int i = 0; it != inputMap.constEnd(); ++it) + { + mArray[i++] = it.value().lanePosition(0); + } + } + } + + GraphLayouter::SceneCoordinateArray::~SceneCoordinateArray() + { + if (mArray) delete [] mArray; + } + + float GraphLayouter::SceneCoordinateArray::lanePosition(int igrid, int ilane) const + { + return mArray[igrid-mFirstIndex] + ilane * sLaneSpacing; + } + float GraphLayouter::EndpointCoordinate::lanePosition(int ilane, bool absolute) const { float y0 = absolute ? mYoffset : mTopPin; @@ -2878,13 +1306,167 @@ namespace hal return false; } - bool GraphLayouter::optimizeNetLayoutEnabled() + bool GraphLayouter::dumpJunctionEnabled() + { + return mDumpJunctions; + } + + void GraphLayouter::setDumpJunctionEnabled(bool enabled) + { + mDumpJunctions = enabled; + } + + void JunctionThread::run() + { + mJunction = new NetLayoutJunction(mEntries); + } + + void DrawNetThread::run() + { + Net* n = gNetlist->get_net_by_id(mId); + if (!n) + return; + + const QHash& wMap = mLayouter->mLaneMap.value(mId); + for (auto it = wMap.constBegin(); it != wMap.constEnd(); ++it) + { + NetLayoutPoint wFromPoint = it.key().endPoint(NetLayoutWire::SourcePoint); + NetLayoutPoint wToPoint = it.key().endPoint(NetLayoutWire::DestinationPoint); + NetLayoutJunction* j0 = mLayouter->mJunctionHash.value(wFromPoint); + NetLayoutJunction* j1 = mLayouter->mJunctionHash.value(wToPoint); + int ilane = it.value(); + int ix0 = wFromPoint.x(); + int iy0 = wFromPoint.y(); + int ix1 = wToPoint.x(); + int iy1 = wToPoint.y(); + + if (it.key().isHorizontal()) + { + float x0 = j0 ? mLayouter->mCoordArrayX->lanePosition(ix0,j0->rect().right()) : mLayouter->mCoordX[ix0].junctionExit(); + float x1 = j1 ? mLayouter->mCoordArrayX->lanePosition(ix1,j1->rect().left()) : mLayouter->mCoordX[ix1].junctionEntry(); + float yy = mLayouter->mCoordArrayY->lanePosition(iy0,ilane); + mLines.appendHLine(x0, x1, yy); + } + else + { + float y0, y1; + float xx = mLayouter->mCoordArrayX->lanePosition(ix0,ilane); + if (wToPoint.isEndpoint()) + { + // netjunction -> endpoint + auto itEpc = mLayouter->mEndpointHash.find(wToPoint); + y0 = j0 ? mLayouter->mCoordArrayY->lanePosition(iy0,j0->rect().bottom()) : mLayouter->mCoordY[iy0].junctionExit(); + y1 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j1->rect().top(), true) : mLayouter->mCoordY[iy1].junctionEntry(); + // if (itEpc==mEndpointHash.constEnd()) + // qDebug() << "xxx to endp" << wToPoint.x() << wToPoint.y() << y0 << y1; + } + else + { + // endpoint -> netjunction + auto itEpc = mLayouter->mEndpointHash.find(wFromPoint); + y0 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j0->rect().bottom(), true) : mLayouter->mCoordY[iy0].junctionExit(); + y1 = j1 ? mLayouter->mCoordArrayY->lanePosition(iy1,j1->rect().top()) : mLayouter->mCoordY[iy1].junctionEntry(); + // if (itEpc==mEndpointHash.constEnd()) + // qDebug() << "xxx fr endp" << wFromPoint.x() << wFromPoint.y() << y0 << y1; + } + if (y1 > y0) + mLines.appendVLine(xx, y0, y1); + } + } + drawJunction(); + drawEndpoint(); + } + + void DrawNetThread::drawJunction() { - return mOptimizeNetLayout; + for (auto jt = mLayouter->mJunctionHash.constBegin(); jt != mLayouter->mJunctionHash.constEnd(); ++jt) + { + auto epcIt = mLayouter->mEndpointHash.find(jt.key()); + int x = jt.key().x(); + int y = jt.key().y(); + bool isEndpoint = (y % 2 == 0); + + for (const NetLayoutJunctionWire& jw : jt.value()->netById(mId).mWires) + { + int li = jw.mIndex.laneIndex(); + if (jw.mIndex.isHorizontal()) + { + Q_ASSERT(epcIt != mLayouter->mEndpointHash.constEnd() || !isEndpoint); + float x0 = mLayouter->mCoordArrayX->lanePosition(x,jw.mRange.first()); + float x1 = mLayouter->mCoordArrayX->lanePosition(x,jw.mRange.last()); + float yy = isEndpoint ? epcIt.value().lanePosition(li, true) : mLayouter->mCoordArrayY->lanePosition(y,li); + mLines.appendHLine(x0, x1, yy); + } + else + { + float y0, y1; + if (!isEndpoint) + { + y0 = mLayouter->mCoordArrayY->lanePosition(y,jw.mRange.first()); + y1 = mLayouter->mCoordArrayY->lanePosition(y,jw.mRange.last()); + } + else if (epcIt != mLayouter->mEndpointHash.constEnd()) + { + y0 = epcIt.value().lanePosition(jw.mRange.first(), true); + y1 = epcIt.value().lanePosition(jw.mRange.last(), true); + } + else + { + y0 = mLayouter->mCoordY.value(y).junctionEntry(); + y1 = mLayouter->mCoordY.value(y).junctionExit(); + if (y1 <= y0) + y1 = y0 + 1; + } + float xx = mLayouter->mCoordArrayX->lanePosition(x,li); + mLines.appendVLine(xx, y0, y1); + } + } + + for (const QPoint& pnt : jt.value()->netById(mId).mKnots) + { + float xp = mLayouter->mCoordArrayX->lanePosition(x,pnt.x()); + float yp = isEndpoint ? epcIt.value().lanePosition(pnt.y(), true) : mLayouter->mCoordArrayY->lanePosition(y,pnt.y()); + mKnots.append(QPointF(xp,yp)); + } + } } - void GraphLayouter::setOptimizeNetLayoutEnabled(bool enabled) + void DrawNetThread::drawEndpoint() { - mOptimizeNetLayout = enabled; + for (auto it = mLayouter->mEndpointHash.constBegin(); it != mLayouter->mEndpointHash.constEnd(); ++it) + { + const GraphLayouter::EndpointCoordinate& epc = it.value(); + + QList inputsById = epc.inputPinIndex(mId); + QList outputsById = epc.outputPinIndex(mId); + if (inputsById.isEmpty() && outputsById.isEmpty()) + continue; + + const NetLayoutJunction* nlj = mLayouter->mJunctionHash.value(it.key()); + int ix = it.key().x(); + float xjLeft = mLayouter->mCoordArrayX->lanePosition(ix,nlj->rect().left()); + float xjRight = mLayouter->mCoordArrayX->lanePosition(ix,nlj->rect().right()); + Q_ASSERT(nlj); + + for (int inpInx : inputsById) + { + if (xjRight >= epc.xInput()) + { + // don't complain if "input" is in fact global output pin + auto ityOut = mLayouter->mGlobalOutputHash.find(mId); + if (ityOut == mLayouter->mGlobalOutputHash.constEnd() || QPoint(mLayouter->mNodeBoundingBox.right() + 1, 2 * ityOut.value()) != it.key()) + qDebug() << "cannot connect input pin" << mId << it.key().x() << it.key().y() / 2 << xjRight << epc.xInput(); + } + else + mLines.appendHLine(xjRight, epc.xInput(), epc.lanePosition(inpInx, true)); + } + for (int outInx : outputsById) + { + if (epc.xOutput() >= xjLeft) + qDebug() << "cannot connect output pin" << mId << it.key().x() << it.key().y() / 2 << xjLeft << epc.xOutput(); + else + mLines.appendHLine(epc.xOutput(), xjLeft, epc.lanePosition(outInx, true)); + } + } } } // namespace hal diff --git a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp index c042f1b72df..d48f9815cf9 100644 --- a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp +++ b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp @@ -1,21 +1,84 @@ +#include "gui/graph_widget/layouters/net_layout_junction.h" +#ifdef JUNCTION_DEBUG +#include #include #include -#include +#endif #include #include #include -#include #include #include #include #include -#include "gui/graph_widget/layouters/net_layout_junction.h" +#include +#include "hal_core/netlist/project_manager.h" + +#ifdef JUNCTION_DEBUG +QMap debugColorMap; QColor colorFromId(u32 netId) { - int hue = (netId-1) * 25; - return QColor::fromHsv(hue,255,255); + QColor retval = debugColorMap.value(netId); + if (!retval.isValid()) + return QColor("white"); + return retval; +} + +void setColorMap(const hal::NetLayoutJunctionEntries& entries) +{ + debugColorMap.clear(); + + QMap pattern; + for (int i=0; i<4; i++) + { + int mask = 1 << i; + for (u32 id : entries.mEntries[i]) + pattern[id] |= mask; + } + QSet danglingWire = { 1, 2, 4, 8}; + int count = 0; + + for (auto it = pattern.begin(); it != pattern.end(); ++it) + { + if (danglingWire.contains(it.value())) + { + debugColorMap[it.key()] = QColor::fromRgb(23,25,29); + continue; + } + + int hue = count++ * 25; + if (hue > 255) + { + int cc = (count-10)%20; + int cd = (count-10)/20; + int h = cc * 10; + int s = 80 - cd*40; + int v = 255; + qDebug() << cc << cd << h << s << v; + if (s <= 0) + { + int g = (20*count) % 128 + 128; + debugColorMap[it.key()] = QColor::fromRgb(g,g,g); + } + else + debugColorMap[it.key()] = QColor::fromHsv(h,s,v); + } + else + debugColorMap[it.key()] = QColor::fromHsv(hue,255,255); + } +} + +QGraphicsEllipseItem* getEllipse(QPoint p, u32 netId) +{ + float dd = DELTA / 2.; + float x0 = FIRST + p.x() * DELTA - dd/2; + float y0 = FIRST + p.y() * DELTA - dd/2; + QGraphicsEllipseItem* retval = new QGraphicsEllipseItem(x0,y0,dd,dd); + retval->setBrush(colorFromId(netId)); + return retval; } +#endif namespace hal { @@ -26,20 +89,21 @@ namespace hal { for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) { int iHoriz = dir.iHorizontal(); - int n = mEntries.size(dir); + int n = mEntries.mEntries[dir.index()].size(); if (n>maxRoad[iHoriz]) maxRoad[iHoriz] = n; for (int i=0; i hNets, vNets; + for (const NetLayoutJunctionWire& nljw : it->mWires ) + if (nljw.mIndex.hvIndex() == LaneIndex::Horizontal) + hNets.append(nljw); + else + vNets.append(nljw); + + for (const NetLayoutJunctionWire& hn : hNets) + for (const NetLayoutJunctionWire& vn : vNets) + if ((hn.mRange.innerPos(vn.mIndex.laneIndex()) && vn.mRange.contains(hn.mIndex.laneIndex())) || + (hn.mRange.contains(vn.mIndex.laneIndex()) && vn.mRange.innerPos(hn.mIndex.laneIndex()))) + it->mKnots.append(QPoint(vn.mIndex.laneIndex(),hn.mIndex.laneIndex())); + } + } void NetLayoutJunction::routeAllMultiPin(NetLayoutDirection leftOrRight) { @@ -59,28 +143,33 @@ namespace hal { for (int iroad=0; iroady1) y1 = y+1; - } - } - if (!mOccupied[1].isEmpty()) - { - for (int x : mOccupied[1].keys()) - { + break; + case LaneIndex::Vertical: + x = ri.laneIndex(); if (xx1) x1 = x+1; + break; } } + + // empty junction has size 1 if (y1<=0) y1 = 1; if (x1<=0) x1 = 1; mRect = QRect(x0,y0,x1-x0,y1-y0); - for (int ihoriz = 0; ihoriz<2; ihoriz++) - for (auto itOcc = mOccupied[ihoriz].constBegin(); itOcc!=mOccupied[ihoriz].constEnd(); ++itOcc) + //TODO: truncate nets to rect might be range function + for (auto itNet = mNets.begin(); itNet != mNets.end(); ++itNet) + { + auto itWire = itNet->mWires.begin(); + while (itWire != itNet->mWires.end()) { - int iroad = itOcc.key(); - for (const NetLayoutJunctionRange& rng : itOcc.value()) - { - NetLayoutJunctionWire w = rng.toWire(ihoriz,iroad); - if (w.mFirst == NetLayoutJunctionRange::sMinInf) - { - if (w.mHorizontal==0) - w.mFirst = x0-1; - else - w.mFirst = y0-1; - } - if (w.mLast == NetLayoutJunctionRange::sMaxInf) - { - if (w.mHorizontal==0) - w.mLast = x1; - else - w.mLast = y1; - } - mNetsOutput[rng.netId()].addWire(w); - } + if (itWire->mRange.first() == NetLayoutJunctionRange::MinInf) + { + if (itWire->mIndex.hvIndex()==LaneIndex::Horizontal) + itWire->mRange.setFirst(x0); + else + itWire->mRange.setFirst(y0); + } + if (itWire->mRange.last() == NetLayoutJunctionRange::MaxInf) + { + if (itWire->mIndex.hvIndex()==LaneIndex::Horizontal) + itWire->mRange.setLast(x1-1); + else + itWire->mRange.setLast(y1-1); + } + if (itWire->mRange.length() <=0) + itWire = itNet->mWires.erase(itWire); + else + ++itWire; } + } } - void NetLayoutJunction::fourWayJunctions(QHash::iterator& netIt) +#ifdef JUNCTION_DEBUG + void NetLayoutJunction::toScene(QGraphicsScene* scene) const { - QList wires[2]; - for (const NetLayoutJunctionWire& w : netIt.value().mWires) - wires[w.mHorizontal].append(w); + scene->setBackgroundBrush(QBrush(QColor::fromRgb(80,80,80))); + QRectF bg(FIRST + (mRect.x() - 0.5) * DELTA, + FIRST + (mRect.y() - 0.5) * DELTA, + mRect.width() * DELTA, + mRect.height() * DELTA); - for (const NetLayoutJunctionWire& hw : wires[0]) + float xscene0 = bg.left() < 100 ? bg.left() - 100 : 0; + float xscene1 = bg.right() > 900 ? bg.right() + 100 : 1000; + float yscene0 = bg.top() < 100 ? bg.top() - 100 : 0; + float yscene1 = bg.bottom() > 900 ? bg.bottom() + 100 : 1000; + scene->setSceneRect(xscene0,yscene0,xscene1,yscene1); + + QGraphicsRectItem* item = new QGraphicsRectItem(bg); + item->setBrush(QBrush(Qt::black)); + scene->addItem(item); + + for (auto netIt = mNets.constBegin(); netIt != mNets.constEnd(); ++netIt) { - if (!hw.isEntry()) continue; - for (const NetLayoutJunctionWire& vw: wires[1]) + for(QPoint jp : netIt.value().junctionPoints()) { - if (!vw.isEntry()) continue; - NetLayoutJunctionWireIntersection pnt = hw.intersection(vw); - if (pnt.isValid()) - { - netIt->setJunctionPoint(pnt); - return; - } + QGraphicsEllipseItem* item = getEllipse(jp,netIt.key()); + scene->addItem(item); } } + + + for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) + { + int nEntries = mEntries.mEntries[dir.index()].size(); + for (int ientry=0; ientrysetPen(QPen(QBrush(col),3.)); + scene->addItem(item); + } + } } - void NetLayoutJunction::dump() const + void NetLayoutJunction::toSceneStep(QGraphicsScene* scene, int istep) { - qDebug() << "-net-"; - for (u32 id : mNetsInput.keys() ) + if (istep >= mOccupied.mHistory.size()) return; + + QRectF bg(FIRST + (mRect.x() - 0.5) * DELTA, + FIRST + (mRect.y() - 0.5) * DELTA, + mRect.width() * DELTA, + mRect.height() * DELTA); + + const QPair& pw = mOccupied.mHistory.at(istep); + QColor col = colorFromId(pw.first); + + float x0, x1, y0, y1; + + const LaneIndex& ri = pw.second.mIndex; + const NetLayoutJunctionRange& rng = pw.second.mRange; + if (ri.hvIndex()==LaneIndex::Horizontal) + { + y0 = y1 = FIRST + ri.laneIndex() * DELTA; + x0 = FIRST + rng.first() * DELTA; + if (x0 < bg.left()) x0 = bg.left(); + x1 = FIRST + rng.last() * DELTA; + if (x1 > bg.right()) x1 = bg.right(); + qDebug() << "---" << ri.laneIndex() << rng.first() << rng.last(); + } + else { - qDebug() << id << mNetsInput.value(id).toString(); + x0 = x1 = FIRST + ri.laneIndex() * DELTA; + y0 = FIRST + rng.first() * DELTA; + if (y0 < bg.top()) y0 = bg.top(); + y1 = FIRST + rng.last() * DELTA; + if (y1 > bg.bottom()) y1 = bg.bottom(); + qDebug() << " | " << ri.laneIndex() << rng.first() << rng.last(); } - qDebug() << mEntries.dump(); + QGraphicsLineItem* item = new QGraphicsLineItem(x0,y0,x1,y1); + item->setPen(QPen(QBrush(col),3.)); + scene->addItem(item); } +#endif void NetLayoutJunction::routeT() { - for (auto itNet=mNetsInput.begin(); itNet!=mNetsInput.end();++itNet) + for (auto itNet=mNets.begin(); itNet!=mNets.end();++itNet) { - if (itNet.value().numberEntries() == 3) + if (itNet.value().numberEntries() >= 3) { - int i0, i1, ilink, ihoriz; + int i0, i1, ilink; + LaneIndex::HVIndex itravers, imaindir; u32 reducedPattern; switch (itNet.value().pattern()) { @@ -246,71 +415,63 @@ namespace hal { i0 = 0; i1 = 1; ilink = 2; - ihoriz = 1; - reducedPattern = itNet.value().roadNumber(i1) > itNet.value().roadNumber(i0) ? 5 : 6; + itravers = LaneIndex::Vertical; + reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 5 : 6; break; case 11: // L D R i0 = 0; i1 = 1; ilink = 3; - ihoriz = 1; - reducedPattern = itNet.value().roadNumber(i1) > itNet.value().roadNumber(i0) ? 10 : 9; + itravers = LaneIndex::Vertical; + reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 10 : 9; break; case 13: // U L D i0 = 2; i1 = 3; ilink = 0; - ihoriz = 0; - reducedPattern = itNet.value().roadNumber(i1) > itNet.value().roadNumber(i0) ? 5 : 9; + itravers = LaneIndex::Horizontal; + reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 5 : 9; break; case 14: // U R D i0 = 2; i1 = 3; ilink = 1; - ihoriz = 0; - reducedPattern = itNet.value().roadNumber(i1) > itNet.value().roadNumber(i0) ? 10 : 6; + itravers = LaneIndex::Horizontal; + reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 10 : 6; break; default: - return; + continue; } - int road0 = itNet.value().roadNumber(i0); - int road1 = itNet.value().roadNumber(i1); - int roadLink = itNet.value().roadNumber(ilink); - int jhoriz = 1-ihoriz; - int roadj; - if (canJoin(jhoriz,road0,itNet.key(),roadLink)) - roadj = road0; - else if (canJoin(jhoriz,road1,itNet.key(),roadLink)) - roadj = road1; - else + int roadLink = itNet.value().laneIndex(ilink); + imaindir = (itravers == LaneIndex::Horizontal ? LaneIndex::Vertical : LaneIndex::Horizontal); + QList mainWires = itNet.value().wireAtPos(roadLink,imaindir); + if (mainWires.isEmpty()) { - int* roadPtr = canJoinAny(jhoriz,itNet.key(),roadLink); - if (roadPtr) - { - roadj = *roadPtr; - delete roadPtr; - } - else + qDebug() << "T-join not found"; + continue; + } + + int minlen = 0; + NetLayoutJunctionRange rngT = NetLayoutJunctionRange::entryRange(ilink,0,itNet.key()); + + for (const NetLayoutJunctionWire& nljw : mainWires) + { + NetLayoutJunctionRange rng = + NetLayoutJunctionRange::entryRange(ilink,nljw.mIndex.laneIndex(),itNet.key()); + if (!minlen || rng.length() < rngT.length()) { - qDebug() << "T-join not found"; - return; + rngT = rng; + minlen = rng.length(); } } - NetLayoutJunctionRange rngT = - NetLayoutJunctionRange::entryRange(ilink,roadj,itNet.key()); - if (conflict(ihoriz,roadLink,rngT)) + if (conflict(LaneIndex(itravers,roadLink),rngT)) itNet->setPattern(reducedPattern); else { - place(ihoriz,roadLink,rngT); + place(LaneIndex(itravers,roadLink),rngT); itNet->setPlaced(); - itNet->setJunctionPoint( - NetLayoutJunctionWireIntersection( - true, - ihoriz?roadLink:roadj, - ihoriz?roadj:roadLink)); } } } @@ -323,8 +484,7 @@ namespace hal { for (auto it = mEntries.mEntries[dirHoriz.index()].begin(); it != mEntries.mEntries[dirHoriz.index()].end(); ++it) { - if (*it == 0) continue; - NetLayoutJunctionNet net = mNetsInput.value(*it); + NetLayoutJunctionNet net = mNets.value(*it); if (net.hasPattern(searchPattern) && !net.isPlaced()) routeSingleCorner(*it,dirHoriz,dirVertic); } @@ -332,8 +492,7 @@ namespace hal { for (auto it = mEntries.mEntries[dirHoriz.index()].rbegin(); it != mEntries.mEntries[dirHoriz.index()].rend(); ++it) { - if (*it == 0) continue; - NetLayoutJunctionNet net = mNetsInput.value(*it); + NetLayoutJunctionNet net = mNets.value(*it); if (net.hasPattern(searchPattern) && !net.isPlaced()) routeSingleCorner(*it,dirHoriz,dirVertic); } @@ -341,135 +500,124 @@ namespace hal { void NetLayoutJunction::routeAllStraight(NetLayoutDirection dirFrom, NetLayoutDirection dirTo) { - QHash straightConnected; + QMap straightConnected; u32 searchPattern = dirFrom.toPattern() | dirTo.toPattern(); - QSet connectedInput, connectedOutput; - QList detourIds; - for (u32 netId : mEntries.mEntries[dirFrom.index()]) { - if (netId==0) continue; - auto itNet = mNetsInput.find(netId); - Q_ASSERT(itNet != mNetsInput.end()); + auto itNet = mNets.find(netId); + Q_ASSERT(itNet != mNets.end()); +// qDebug () << "straight" << searchPattern << netId << itNet.value().hasPattern(searchPattern) << itNet.value().pattern(); if (itNet.value().hasPattern(searchPattern)) { - int iroadIn = itNet.value().roadNumber(dirFrom); - int iroadOut = itNet.value().roadNumber(dirTo); - if (connectedInput.contains(iroadOut) && connectedOutput.contains(iroadIn)) - { - // swap detected, cannot route directly - detourIds.append(netId); - continue; - } - routeSingleStraight(netId, (searchPattern==3?0:1), iroadIn, iroadOut); - straightConnected[iroadIn] = iroadOut; + int iroadIn = itNet.value().laneIndex(dirFrom); + int iroadOut = itNet.value().laneIndex(dirTo); + if (straightConnected.contains(iroadIn) && straightConnected.contains(iroadOut)) + routeSingleSwap(netId, (searchPattern==3?0:1), iroadIn, iroadOut); + else + routeSingleStraight(netId, (searchPattern==3?0:1), iroadIn, iroadOut); + ++straightConnected[iroadIn]; + ++straightConnected[iroadOut]; if (itNet.value().numberEntries() % 2 ==0) itNet->setPlaced(); - connectedInput.insert(iroadIn); - connectedOutput.insert(iroadOut); } } - - for (u32 netId : detourIds) - { - auto itNet = mNetsInput.find(netId); - Q_ASSERT(itNet != mNetsInput.end()); - int iroadIn = itNet.value().roadNumber(dirFrom); - int iroadOut = itNet.value().roadNumber(dirTo); - routeSingleDetour(netId, (searchPattern==3?0:1), iroadIn, iroadOut); - straightConnected[iroadIn] = iroadOut; - if (itNet.value().numberEntries() % 2 ==0) - itNet->setPlaced(); - } } - bool NetLayoutJunction::conflict(int ihoriz, int iroad, const NetLayoutJunctionRange& testRng) const + bool NetLayoutJunction::conflict(const LaneIndex&ri, const NetLayoutJunctionRange& testRng) const { - auto itConflict = mOccupied[ihoriz].find(iroad); - if (itConflict == mOccupied[ihoriz].end()) return false; + auto itConflict = mOccupied.find(ri); + if (itConflict == mOccupied.end()) return false; return itConflict.value().conflict(testRng); } - bool NetLayoutJunction::canJoin(int ihoriz, int iroad, u32 netId, int pos) const + bool NetLayoutJunction::canJoin(const LaneIndex &ri, u32 netId, int pos) const { - auto itJoin = mOccupied[ihoriz].find(iroad); - if (itJoin == mOccupied[ihoriz].end()) return false; + auto itJoin = mOccupied.find(ri); + if (itJoin == mOccupied.end()) return false; return itJoin.value().canJoin(netId,pos); } - int* NetLayoutJunction::canJoinAny(int ihoriz, u32 netId, int pos) const + void NetLayoutJunction::place(const LaneIndex &ri, const NetLayoutJunctionRange &range) { - for (auto itTry = mOccupied[ihoriz].constBegin(); itTry != mOccupied[ihoriz].constEnd(); ++itTry) + NetLayoutJunctionOccupiedHash::AddOrMerge aom = mOccupied.addOrMerge(ri,range); + + auto netIt = mNets.find(range.netId()); + Q_ASSERT(netIt!=mNets.end()); + switch (aom.mType ) { - if (itTry.value().canJoin(netId,pos)) - { - int* retval = new int; - *retval = itTry.key(); - return retval; - } + case NetLayoutJunctionOccupiedHash::AddOrMerge::Added: + { + NetLayoutJunctionWire nljw(range,ri); + netIt->addWire(nljw); + break; + } + case NetLayoutJunctionOccupiedHash::AddOrMerge::Merged: + { + NetLayoutJunctionWire nljw(*aom.mNewRange,ri); + netIt->replaceWire(*aom.mOldRange,nljw); + break; + } + default: + break; } - return nullptr; - } - - void NetLayoutJunction::place(int ihoriz, int iroad, const NetLayoutJunctionRange &range) - { - mOccupied[ihoriz][iroad].append(range); - auto netIt = mNetsInput.find(range.netId()); - Q_ASSERT(netIt!=mNetsInput.end()); - netIt->addWire(NetLayoutJunctionWire(ihoriz,iroad, - range.endPosition(0), - range.endPosition(1))); } - void NetLayoutJunction::routeSingleDetour(u32 netId, int iMain, int iroadIn, int iroadOut) + void NetLayoutJunction::routeSingleSwap(u32 netId, int iMain, int iroadIn, int iroadOut) { int iJump = 1-iMain; int iroadJump0 = -1; int iroadJump1 = maxRoad[iJump]; int iroadDetour = maxRoad[iMain]; - int maxSearch = std::max(2*(maxRoad[0]+maxRoad[1]),12)*3; - int count = 0; - while (count++ < maxSearch) // break when route found - { - NetLayoutJunctionRange rngIn(netId, NetLayoutJunctionRange::sMinInf, iroadJump0); - NetLayoutJunctionRange rngJ0(netId, iroadIn, iroadDetour); - NetLayoutJunctionRange rngDt(netId, iroadJump0, iroadJump1); - NetLayoutJunctionRange rngJ1(netId, iroadOut, iroadDetour); - NetLayoutJunctionRange rngOut(netId, iroadJump1, NetLayoutJunctionRange::sMaxInf); - if (conflict(iMain,iroadDetour,rngDt)) + + LaneIndex riDetour(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadDetour); + LaneIndex riJump0(iJump?LaneIndex::Vertical:LaneIndex::Horizontal,iroadJump0); + LaneIndex riJump1(iJump?LaneIndex::Vertical:LaneIndex::Horizontal,iroadJump1); + LaneIndex riMainIn(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadIn); + LaneIndex riMainOut(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadOut); + + for (;;) // break when route found + { + NetLayoutJunctionRange rngIn(netId, NetLayoutJunctionRange::MinInf, riJump0.laneIndex()); + NetLayoutJunctionRange rngJ0(netId, iroadIn, riDetour.laneIndex()); + NetLayoutJunctionRange rngDt(netId, riJump0.laneIndex(), riJump1.laneIndex()); + NetLayoutJunctionRange rngJ1(netId, iroadOut, riDetour.laneIndex()); + NetLayoutJunctionRange rngOut(netId, riJump1.laneIndex(), NetLayoutJunctionRange::MaxInf); + + + if (conflict(riDetour,rngDt)) { - iroadDetour ++; + ++riDetour; continue; } - if (conflict(iJump,iroadJump1,rngJ1) || - conflict(iMain,iroadOut,rngOut)) + if (conflict(riJump1,rngJ1) || + conflict(riMainOut,rngOut)) { - iroadJump1 ++; + ++riJump1; continue; } - if (conflict(iJump,iroadJump0,rngJ0) || - conflict(iMain,iroadIn,rngIn)) + if (conflict(riJump0,rngJ0) || + conflict(riMainIn,rngIn)) { - iroadJump0 --; + --riJump0; continue; } - place(iMain,iroadIn,rngIn); - place(iJump,iroadJump0,rngJ0); - place(iMain,iroadDetour,rngDt); - place(iJump,iroadJump1,rngJ1); - place(iMain,iroadOut,rngOut); + place(riMainIn,rngIn); + place(riJump0,rngJ0); + place(riDetour,rngDt); + place(riJump1,rngJ1); + place(riMainOut,rngOut); break; } } void NetLayoutJunction::routeSingleStraight(u32 netId, int iMain, int iroadIn, int iroadOut) - { + { int iJump = 1-iMain; if (iroadIn == iroadOut) { - NetLayoutJunctionRange rng(netId,NetLayoutJunctionRange::sMinInf, NetLayoutJunctionRange::sMaxInf); - place(iMain,iroadIn,rng); + NetLayoutJunctionRange rng(netId,NetLayoutJunctionRange::MinInf, NetLayoutJunctionRange::MaxInf); + place(LaneIndex(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadIn),rng); return; } int iroadLo = iroadIn; @@ -483,67 +631,102 @@ namespace hal { iroadJump = maxRoad[iJump]; isearchIncr = 1; } - int maxSearch = std::max(2*(maxRoad[0]+maxRoad[1]),12); for (;;iroadJump+=isearchIncr) { - if (iroadJump <= -maxSearch || - iroadJump >= maxSearch) + if (iroadJump <= NetLayoutJunctionRange::MinInf || + iroadJump >= NetLayoutJunctionRange::MaxInf) { - mError = StraightRouteError; + qDebug() << "cannot route straight" << (iMain ? "vertical" : "horizontal") + << netId << iroadIn << iroadOut; return; } NetLayoutJunctionRange rngIn(netId, - NetLayoutJunctionRange::sMinInf, + NetLayoutJunctionRange::MinInf, iroadJump); NetLayoutJunctionRange rngJump(netId, iroadLo, iroadHi); NetLayoutJunctionRange rngOut(netId, iroadJump, - NetLayoutJunctionRange::sMaxInf); + NetLayoutJunctionRange::MaxInf); + + LaneIndex riJump(iJump?LaneIndex::Vertical:LaneIndex::Horizontal,iroadJump); + LaneIndex riMainIn(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadIn); + LaneIndex riMainOut(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadOut); + if (!conflict(riJump,rngJump) && + !conflict(riMainOut,rngOut) && + !conflict(riMainIn,rngIn)) + { + place(riJump,rngJump); + place(riMainIn,rngIn); + place(riMainOut,rngOut); + break; + } + } + } + + NetLayoutJunctionOccupiedHash::AddOrMerge NetLayoutJunctionOccupiedHash::addOrMerge(const LaneIndex& ri, const NetLayoutJunctionRange &rng) + { + // operator will create entry if not existing + NetLayoutJunctionOccupied& nljo = this->operator[](ri); + + AddOrMerge retval; - if (!conflict(iJump,iroadJump,rngJump) && - !conflict(iMain,iroadOut,rngOut) && - !conflict(iMain,iroadIn,rngIn)) + for (auto it = nljo.begin(); it!= nljo.end(); ++it) + { + if (*it == rng) { - place(iJump,iroadJump,rngJump); - place(iMain,iroadIn,rngIn); - place(iMain,iroadOut,rngOut); + retval.mType = AddOrMerge::AlreadyExisting; + break; + } + if (it->canJoin(rng)) + { + retval.mOldRange = new NetLayoutJunctionRange(*it); + it->expand(rng); + retval.mNewRange = new NetLayoutJunctionRange(*it); + retval.mType = AddOrMerge::Merged; break; } } + + if (retval.mType == AddOrMerge::Added) + nljo.append(rng); + +#ifdef JUNCTION_DEBUG + mHistory.append(qMakePair(rng.netId(),NetLayoutJunctionWire(rng,ri))); +#endif + return retval; } void NetLayoutJunction::routeSingleCorner(u32 netId, NetLayoutDirection dirHoriz, NetLayoutDirection dirVertic) { - auto netIt = mNetsInput.find(netId); - Q_ASSERT(netIt != mNetsInput.end()); + auto netIt = mNets.find(netId); + Q_ASSERT(netIt != mNets.end()); - int iroadHoriz = netIt.value().roadNumber(dirHoriz); - int iroadVertic = netIt.value().roadNumber(dirVertic); + int iroadHoriz = netIt.value().laneIndex(dirHoriz); + int iroadVertic = netIt.value().laneIndex(dirVertic); + // Try to connect straight lines directly without detour NetLayoutJunctionRange rngH = NetLayoutJunctionRange::entryRange(dirHoriz,iroadVertic,netId); NetLayoutJunctionRange rngV = NetLayoutJunctionRange::entryRange(dirVertic,iroadHoriz,netId); - if (!conflict(0,iroadHoriz,rngH) && !conflict(1,iroadVertic,rngV)) - { - netIt->setJunctionPoint( - NetLayoutJunctionWireIntersection( - true, - iroadVertic, - iroadHoriz), - NetLayoutJunctionWireIntersection::Endpoint); - mOccupied[0][iroadHoriz].append(rngH); - mOccupied[1][iroadVertic].append(rngV); + if (!conflict(LaneIndex::horizontal(iroadHoriz),rngH) && !conflict(LaneIndex::vertical(iroadVertic),rngV)) + { + place(LaneIndex::horizontal(iroadHoriz),rngH); + place(LaneIndex::vertical(iroadVertic),rngV); netIt->setPlaced(); return; } + // OK, we need around corner detour int hcroad = dirVertic.isUp() ? -1 : mEntries.mEntries[dirHoriz.index()].size(); int hstep = dirVertic.isUp() ? -1 : 1; int vcroad = dirHoriz.isLeft() ? -1 : mEntries.mEntries[dirVertic.index()].size(); int vstep = dirHoriz.isLeft() ? -1 : 1; int icount = 0; + int tryMax = 2 * mOccupied.size(); + for (int i=0; i<4; i++) + tryMax += 2* mEntries.mEntries[i].size(); for(;;) { NetLayoutJunctionRange rngVc(netId,iroadHoriz,hcroad); @@ -553,53 +736,32 @@ namespace hal { NetLayoutJunctionRange rngVe = NetLayoutJunctionRange::entryRange(dirVertic,hcroad,netId); - if (++icount > 12 && icount > 2*(maxRoad[0]+maxRoad[1])) + if (++icount > tryMax) { + qDebug() << "giving up"; mError = CornerRouteError; return; } // qDebug() << "try" << netId << iroadHoriz << iroadVertic << hcroad << vcroad; - if (conflict(0,hcroad,rngHc) || conflict(1,iroadVertic,rngVe)) + if (conflict(LaneIndex::horizontal(hcroad),rngHc) || conflict(LaneIndex::vertical(iroadVertic),rngVe)) hcroad += hstep; - else if (conflict(1,vcroad,rngVc) || conflict(0,iroadHoriz,rngHe)) + else if (conflict(LaneIndex::vertical(vcroad),rngVc) || conflict(LaneIndex::horizontal(iroadHoriz),rngHe)) vcroad += vstep; else { - if(netIt->numberEntries()==3) - { - netIt->setJunctionPoint( - NetLayoutJunctionWireIntersection( - true, - vcroad, - iroadHoriz), - NetLayoutJunctionWireIntersection::Verify); - netIt->setJunctionPoint( - NetLayoutJunctionWireIntersection( - true, - iroadVertic, - hcroad), - NetLayoutJunctionWireIntersection::Verify); - } - place(0,hcroad,rngHc); - place(1,vcroad,rngVc); - place(0,iroadHoriz,rngHe); - place(1,iroadVertic,rngVe); - mOccupied[1][vcroad].append(rngVc); - mOccupied[0][iroadHoriz].append(rngHe); - mOccupied[1][iroadVertic].append(rngVe); + place(LaneIndex::horizontal(hcroad),rngHc); + place(LaneIndex::vertical(vcroad),rngVc); + + place(LaneIndex::horizontal(iroadHoriz),rngHe); + place(LaneIndex::vertical(iroadVertic),rngVe); netIt->setPlaced(); break; } } } - NetLayoutJunctionHash::~NetLayoutJunctionHash() - { - clearAll(); - } - void NetLayoutJunctionHash::clearAll() { for (NetLayoutJunction* nlj : values()) @@ -607,17 +769,18 @@ namespace hal { clear(); } + NetLayoutJunctionNet::NetLayoutJunctionNet() : mPattern(0), mEntries(0), mPlaced(false) { for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) - mRoadNumber[dir.index()] = -1; + mLaneIndex[dir.index()] = -1; } - void NetLayoutJunctionNet::addEntry(NetLayoutDirection dir, int roadNo) + void NetLayoutJunctionNet::addEntry(NetLayoutDirection dir, int laneInx) { mPattern |= dir.toPattern(); - mRoadNumber[dir.index()] = roadNo; + mLaneIndex[dir.index()] = laneInx; ++mEntries; } @@ -626,49 +789,24 @@ namespace hal { return (mPattern & searchPattern) == searchPattern; } - void NetLayoutJunctionNet::setJunctionPoint(const NetLayoutJunctionWireIntersection& jp, - NetLayoutJunctionWireIntersection::PlacementType placement) + void NetLayoutJunctionNet::replaceWire(const NetLayoutJunctionRange &rng, const NetLayoutJunctionWire &wire) { - bool found = false; - - switch (placement) - { - case NetLayoutJunctionWireIntersection::Verify: - for (const NetLayoutJunctionWire& wire : mWires) + for (auto it = mWires.begin(); it!= mWires.end(); ++it) + if (rng == *it) { - if (wire.isEntry() && - ((wire.mRoad == jp.x() && wire.mHorizontal == 1) || - (wire.mRoad == jp.y() && wire.mHorizontal == 0)) - ) - { - found = true; - break; - } - } - if (!found) return; - mJunction = jp; - break; - case NetLayoutJunctionWireIntersection::Endpoint: - for (const NetLayoutJunctionWire& wire : mWires) - { - if (wire.isEntry() && wire.mRoad == jp.x() && wire.mHorizontal==1) - { - mJunction = NetLayoutJunctionWireIntersection(true, jp.x(), wire.centralEnd()); - return; - } - if (wire.isEntry() && wire.mRoad == jp.y() && wire.mHorizontal==0) - { - mJunction = NetLayoutJunctionWireIntersection(true, wire.centralEnd(), jp.y()); - return; - } + *it = wire; + return; } - break; - default: - mJunction = jp; - break; - } } + QList NetLayoutJunctionNet::wireAtPos(int pos, LaneIndex::HVIndex hvi) + { + QList retval; + for (auto it = mWires.begin(); it!= mWires.end(); ++it) + if (it->mIndex.hvIndex() == hvi && it->mRange.contains(pos)) + retval.append(*it); + return retval; + } QString NetLayoutJunctionNet::toString() const { @@ -679,45 +817,29 @@ namespace hal { if (mPattern & dir.toPattern()) { if (!retval.isEmpty()) retval += ":"; - retval += QString("%1%2").arg(dirChar[dir.index()]).arg(mRoadNumber[dir.index()]); + retval += QString("%1%2").arg(dirChar[dir.index()]).arg(mLaneIndex[dir.index()]); } } return retval; } - QGraphicsEllipseItem* NetLayoutJunctionWireIntersection::graphicsFactory(u32 netId) const - { - float dd = NetLayoutJunctionRange::sSceneDelta / 2.; - float x0 = NetLayoutJunctionRange::sSceneFirst + x() * NetLayoutJunctionRange::sSceneDelta - dd/2; - float y0 = NetLayoutJunctionRange::sSceneFirst + y() * NetLayoutJunctionRange::sSceneDelta - dd/2; - QGraphicsEllipseItem* retval = new QGraphicsEllipseItem(x0,y0,dd,dd); - retval->setBrush(colorFromId(netId)); - return retval; - } - - NetLayoutJunctionRange::NetLayoutJunctionRange(u32 netId_, int first, int last) : mNetId(netId_), mFirst(first), mLast(last) { - if (last mLast) mLast = other.mLast; } - void NetLayoutJunctionOccupied::add(const NetLayoutJunctionRange& rng) - { - for (auto it = begin(); it!= end(); ++it) - if (it->canJoin(rng)) - { - it->expand(rng); - return; - } - append(rng); - } - bool NetLayoutJunctionOccupied::canJoin(u32 netId, int pos) const { for (const NetLayoutJunctionRange& r : *this) - if (r.canJoin(netId, pos)) return true; + { + if (r.netId() != netId) continue; + if (r.contains(pos)) return true; + } return false; } @@ -801,32 +903,27 @@ namespace hal { return false; } - int NetLayoutJunctionWire::centralEnd() const - { - if (mFirst==NetLayoutJunctionRange::sMinInf) - return mLast; - return mFirst; - } - bool NetLayoutJunctionWire::isEntry() const { - return mFirst == NetLayoutJunctionRange::sMinInf - || mLast == NetLayoutJunctionRange::sMaxInf; + return mRange.isEntry(0) || mRange.isEntry(1); } - NetLayoutJunctionWireIntersection NetLayoutJunctionWire::intersection(const NetLayoutJunctionWire &other) const + void NetLayoutJunctionEntries::dumpToFile(const QPoint &pnt) const { - if (other.mFirst <= mRoad && mRoad <= other.mLast && - mFirst <= other.mRoad && other.mRoad <= mLast) + QFile ff(QString::fromStdString(ProjectManager::instance()->get_project_directory().get_filename("junction_data.txt").string())); + if (!ff.open(QIODevice::WriteOnly | QIODevice::Append)) return; + QTextStream xout(&ff); + xout << "(" << pnt.x() << "," << pnt.y() << ")\n"; + for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) { - if (mHorizontal) - return NetLayoutJunctionWireIntersection(true,mRoad,other.mRoad); - return NetLayoutJunctionWireIntersection(true,other.mRoad,mRoad); + for (u32 id : mEntries[dir.index()]) + xout << " " << id; + xout << "\n"; } - return NetLayoutJunctionWireIntersection(); + xout.flush(); } - QString NetLayoutJunctionEntries::dump() const + QString NetLayoutJunctionEntries::toString() const { QString retval; for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) @@ -839,38 +936,5 @@ namespace hal { return retval; } - void NetLayoutJunctionEntries::dumpFile(const NetLayoutPoint& pnt) const - { - QString filename("/tmp/junction"); - QDir().mkpath(filename); - QString columnStr; - int ix = pnt.x(); - if (ix < 0) - { - columnStr += "_"; - ix = -ix; - } - if (ix >= 26) columnStr += QString("%1").arg((char)('A'+ ix/26 - 1)); - columnStr += QString("%1").arg((char)('A'+ ix%26)); - int iy = pnt.y(); - if (iy < 0) - { - columnStr += "_"; - iy = -iy; - } - filename += "/" + columnStr + QString("%1.jjj").arg(iy); - QFile ff(filename); - if (!ff.open(QIODevice::WriteOnly)) return; - for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) - { - for (u32 id : mEntries[dir.index()]) - ff.write(" " + QByteArray::number(id)); - ff.write("\n"); - } - } - - void NetLayoutJunctionEntries::setEntries(NetLayoutDirection dir, const QList& entries_) - { - mEntries[dir.index()] = entries_; - } + uint qHash(const LaneIndex& ri) { return ri.mIndex; } } // namespace hal diff --git a/plugins/gui/src/graph_widget/layouters/net_layout_point.cpp b/plugins/gui/src/graph_widget/layouters/net_layout_point.cpp index 00335a13e16..4d4e0478699 100644 --- a/plugins/gui/src/graph_widget/layouters/net_layout_point.cpp +++ b/plugins/gui/src/graph_widget/layouters/net_layout_point.cpp @@ -203,6 +203,12 @@ bool NetLayoutWire::operator==(const NetLayoutWire& other) const mIsEndpoint==other.mIsEndpoint); } +QString NetLayoutWire::toString() const +{ + static const char* cdir = "LRUD"; + return QString("<%1,%2>-%3-%4").arg(mPoint.x()).arg(mPoint.y()).arg(cdir[mDir.index()]).arg(mIsEndpoint?'X':'-'); +} + QGraphicsLineItem* NetLayoutWire::graphicsFactory() const { if (mDir.isNull()) return nullptr; @@ -405,7 +411,6 @@ NetLayoutConnectionFactory::NetLayoutConnectionFactory(const QList