HAL  v4.5.0-133-g64838ea8d
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
net_layout_point.cpp
Go to the documentation of this file.
3 #include <QGraphicsEllipseItem>
4 #include <QGraphicsLineItem>
5 #include <QBrush>
6 #include <QPen>
7 #include <QSet>
8 #include <QMultiMap>
9 #include <stdlib.h>
10 #include <QDebug>
11 #include <QTextStream>
12 #include <QIODevice>
13 
15 {
16  return QPointF(
17  p.x() * 200 + 50,
18  p.y() * 100 + 50);
19 }
20 
21 namespace hal {
22 
23 uint qHash(const hal::NetLayoutPoint& p)
24 {
25  return QtCompat::qHashPoint(static_cast<QPoint>(p));
26 }
27 
28 uint qHash(const hal::NetLayoutWire& w)
29 {
30  uint retval = qHash(w.endPoint(NetLayoutWire::SourcePoint)) << 1;
31  return retval + (w.isHorizontal() ? 1 : 0);
32 }
33 
34 //------------ Direction -----------------
36  : mDir(numberToDirection(idir))
37 {;}
38 
39 NetLayoutDirection::DirectionType NetLayoutDirection::numberToDirection(int idir)
40 {
41  if (idir < Left || idir > MaxDir) return Undefined;
42  return static_cast<DirectionType>(idir);
43 }
44 
46 {
47  NetLayoutDirection retval = *this;
48  mDir = numberToDirection(mDir + 1);
49  return retval;
50 }
51 
53 {
54  mDir = numberToDirection(mDir + 1);
55  return *this;
56 }
57 
58 QPoint NetLayoutDirection::step(bool omitEndpoint) const
59 {
60  int dy = omitEndpoint ? 2 : 1;
61  switch (mDir) {
62  case Left:
63  return QPoint(-1,0);
64  case Right:
65  return QPoint(1,0);
66  case Up:
67  return QPoint(0,-dy);
68  case Down:
69  return QPoint(0,dy);
70  default:
71  break;
72  }
73  return QPoint();
74 }
75 
76 //------------ Point ---------------------
78  : QPoint(x_,y_)
79 {;}
80 
82  : QPoint(p)
83 {;}
84 
85 NetLayoutPoint NetLayoutPoint::nextPoint(const NetLayoutDirection& dir, bool omitEndpoint) const
86 {
87  QPoint p(*this);
88  return NetLayoutPoint(p + dir.step(omitEndpoint));
89 }
90 
92 {
93  if (y()<0)
94  return (y() - 1) / 2;
95  return (y() + 1) / 2;
96 }
97 
98 NetLayoutPoint NetLayoutPoint::fromBox(const QPoint& boxPosition, bool isInput)
99 {
100  return NetLayoutPoint(boxPosition.x() + (isInput?0:1), boxPosition.y() * 2);
101 }
102 
104 {
105  return y() % 2 == 0;
106 }
107 
109 {
110  int dy = abs(other.y()-y());
111  int dx = abs(other.x()-x());
112  if (isEndpoint())
113  {
114  --dy;
115  if (dy<0)
116  {
117  if (dx==0) return 0;
118  dy = 1;
119  }
120  ++dy;
121  }
122  return dy*2 + dx*4;
123 }
124 
126 {
127  QPointF p0 = scenePoint(*this) - QPointF(r/2,r/2);
128  QGraphicsEllipseItem* retval = new QGraphicsEllipseItem(p0.x(),p0.y(),r,r);
129  retval->setPen(QPen(QBrush(Qt::black),1.));
130  return retval;
131 }
132 
134 {
135  QMultiMap<int, QPair<int,int> > distanceMap;
136  QList<NetLayoutPoint> retval;
137  QSet<int> placed;
138 
139  int n = points.size();
140  for (int i=1; i<n; i++)
141  for (int j=0; j<i; j++)
142  distanceMap.insert(points.at(i).distanceTo(points.at(j)), qMakePair(i,j));
143 
144  /*
145  for (auto it = distanceMap.begin(); it != distanceMap.end(); ++it)
146  {
147  int i = it.value().first;
148  int j = it.value().second;
149  qDebug() << it.key() << i << j << (QPoint) points.at(i) << (QPoint) points.at(j);
150  }
151  */
152 
153  bool isFirst = true;
154  while (retval.size() < points.size())
155  {
156  auto it = distanceMap.begin();
157  if (isFirst)
158  isFirst = false;
159  else
160  {
161  // search entry where exactly one has been placed
162  while(it != distanceMap.end() &&
163  placed.contains(it.value().first) == placed.contains(it.value().second))
164  ++it;
165  }
166 
167  for (int ipair=0; ipair<2; ipair++)
168  {
169  int i = ipair ? it.value().second : it.value().first;
170  if (!placed.contains(i))
171  {
172  retval.append(points.at(i));
173  placed.insert(i);
174  }
175  }
176  distanceMap.erase(it);
177  }
178 
179  return retval;
180 }
181 
182 //------------ Wire ----------------------
184  : mPoint(p), mDir(dir), mIsEndpoint(isEnd)
185 {
186  switch (dir.direction())
187  {
189  mPoint = p.nextPoint(dir);
191  break;
193  mPoint = p.nextPoint(dir, !isEnd);
195  break;
196  default:
197  break;
198  }
199 }
200 
201 bool NetLayoutWire::operator==(const NetLayoutWire& other) const
202 {
203  return (mPoint==other.mPoint &&
204  mDir==other.mDir &&
205  mIsEndpoint==other.mIsEndpoint);
206 }
207 
209 {
210  static const char* cdir = "LRUD";
211  return QString("<%1,%2>-%3-%4").arg(mPoint.x()).arg(mPoint.y()).arg(cdir[mDir.index()]).arg(mIsEndpoint?'X':'-');
212 }
213 
215 {
216  if (mDir.isNull()) return nullptr;
217  NetLayoutPoint p = mPoint.nextPoint(mDir,!mIsEndpoint);
218  QPointF p0 = scenePoint(mPoint);
219  QPointF p1 = scenePoint(p);
220  QGraphicsLineItem* retval = new QGraphicsLineItem(QLineF(p0,p1));
221  retval->setPen(QPen(QBrush(Qt::black),3.));
222  return retval;
223 }
224 
226 {
227  if (pnt == SourcePoint) return mPoint;
228  return NetLayoutPoint(static_cast<QPoint>(mPoint)+mDir.step(!mIsEndpoint));
229 }
230 
231 //------------ Connection ----------------
233 {
234  NetLayoutDirection hDir, vDir;
235 
236  if (pa==pb)
237  {
238  // connection has one junction point and no wire
239  mWaypointLinks.insert(pa,QList<int>());
240  return;
241  }
242 
243  NetLayoutPoint waypoint = pa;
244  int dx = pb.x() - pa.x();
245  int dy = pb.y() - pa.y();
246 
247  NetLayoutDirection vdir, hdir;
248 
249  if (pa.isEndpoint())
250  {
252  waypoint = addWire(waypoint, vdir, false);
253  }
254 
255  if (dx)
256  {
258  for (int i=0; i<abs(dx); i++)
259  waypoint = addWire(waypoint, hdir, true);
260  }
261 
262  dy = pb.y() - waypoint.y();
263  if (abs(dy) > 1)
264  {
266  int ysteps = abs(dy) / 2;
267  for (int i=0; i<ysteps; i++)
268  waypoint = addWire(waypoint, vdir, true);
269  }
270 
271  if (pb.isEndpoint())
272  {
273  dy = pb.y() - waypoint.y();
275  addWire(waypoint, vdir, false);
276  }
277 }
278 
280 {
281  NetLayoutPoint retval;
282  int bestDistance = 0;
283  for (const NetLayoutPoint& testP : mWaypointLinks.keys())
284  {
285  if (testP.isUndefined()) continue;
286  int distance = pnt.distanceTo(testP);
287  if (retval.isUndefined() || distance < bestDistance)
288  {
289  bestDistance = distance;
290  retval = testP;
291  }
292  }
293  if (retval.isUndefined())
294  {
295  qDebug() << "undefined closest point" << pnt.x() << pnt.y();
296  for (const NetLayoutPoint& testP : mWaypointLinks.keys())
297  qDebug() << (QPoint) testP;
298  qDebug() << "-----------";
299  }
300  return retval;
301 }
302 
303 void NetLayoutConnection::add(const NetLayoutConnection& other, bool atomicNet)
304 {
305  for (const NetLayoutWire& w : other)
306  {
307  int n = size();
308  if (atomicNet && !w.isHorizontal() && !w.isEndpoint())
309  {
310  // split vertical wires so that only atomic parts get stored
316  append(wA);
317  append(wB);
318  mWaypointLinks[pA].append(n);
319  mWaypointLinks[pB].append(n);
320  mWaypointLinks[pB].append(n+1);
321  mWaypointLinks[pC].append(n+1);
322  }
323  else
324  {
325  append(w);
326  mWaypointLinks[w.endPoint(NetLayoutWire::SourcePoint)].append(n);
327  mWaypointLinks[w.endPoint(NetLayoutWire::DestinationPoint)].append(n);
328  }
329  }
330 }
331 
332 NetLayoutPoint NetLayoutConnection::addWire(const NetLayoutPoint &pnt, const NetLayoutDirection &dir, bool omitEndpoint)
333 {
334  int n = size();
335  append(NetLayoutWire(pnt,dir,!omitEndpoint));
336  mWaypointLinks[pnt].append(n);
337  NetLayoutPoint nextP = pnt.nextPoint(dir,omitEndpoint);
338  mWaypointLinks[nextP].append(n);
339  return nextP;
340 }
341 
342 //------------ Metric --------------------
344  : mId(id), mFirst(0), mSecond(0)
345 {
346  QMap<int,QMap<int,int>> horizontalMap;
347  QMap<int,QMap<int,int>> verticalMap;
348 
349  for (const NetLayoutWire& w : *con)
350  {
352  if (w.isHorizontal())
353  horizontalMap[p.y()].insert(p.x(),0);
354  else
355  verticalMap[p.x()].insert(p.y(),0);
356  }
357  evaluate(horizontalMap);
358  evaluate(verticalMap);
359 }
360 
362 {
363  if (mSecond > other.mSecond) return true;
364  if (mSecond < other.mSecond) return false;
365  if (mFirst > other.mFirst) return true;
366  if (mFirst < other.mFirst) return false;
367  return (mId < other.mId);
368 }
369 
370 void NetLayoutMetric::evaluate(const QMap<int, QMap<int, int> >& map)
371 {
372  for (QMap<int,int> set : map.values() )
373  {
374  while (!set.isEmpty())
375  {
376 
377  auto it = set.begin();
378  int q = it.key() + 1;
379  int n = 0;
380  auto jt = set.find(q);
381  while (jt != set.end())
382  {
383  ++q;
384  ++n;
385  set.erase(jt);
386  jt = set.find(q);
387  }
388  mFirst += n;
389  mSecond += n*n;
390  set.erase(it);
391  }
392  }
393 }
394 
395 //------------ Factory -------------------
397  : connection(nullptr), mSources(sources), mDestinations(destinations)
398 {
399  mPoints.append(mSources);
400  mPoints.append(mDestinations);
401  mPoints = NetLayoutPoint::orderByDistance(mPoints);
402 
403  /*
404  for (const NetLayoutPoint& p : mPoints)
405  {
406  qDebug() << "point" << (QPoint) p;
407  }
408 */
409 
410  int n=mPoints.size();
411  NetLayoutConnection seedConnection(mPoints.at(0),mPoints.at(1));
412  for (int i=2; i<n; i++)
413  {
414  const NetLayoutPoint& nextPoint = mPoints.at(i);
415  const NetLayoutPoint& juncPoint = seedConnection.closestPoint(nextPoint);
416  NetLayoutConnection nextConnection(nextPoint,juncPoint);
417  seedConnection.add(nextConnection,false);
418  }
420  connection->add(seedConnection,true);
421 }
422 
424 {
425  QTextStream xout(stdout, QIODevice::WriteOnly);
426  xout << stub << "\n";
427  xout << "src:";
428  for (const NetLayoutPoint& pnt : mSources)
429  {
430  xout << QString(" <%1,%2>").arg(pnt.x()).arg(pnt.y());
431  }
432  xout << "\ndst:";
433  for (const NetLayoutPoint& pnt : mDestinations)
434  {
435  xout << QString(" <%1,%2>").arg(pnt.x()).arg(pnt.y());
436  }
437  xout << "\nwire:";
438  for (const NetLayoutWire& w : *connection)
439  {
440  xout << QString(" <%1,%2>%3")
441  .arg(w.endPoint(NetLayoutWire::SourcePoint).x())
442  .arg(w.endPoint(NetLayoutWire::SourcePoint).y())
443  .arg(w.isHorizontal()?'-':'|');
444  }
445  xout << "\n===========================\n";
446 }
447 
449 {
450  clearAll();
451 }
452 
454 {
455  for (NetLayoutConnection* nlc : values())
456  delete nlc;
457  clear();
458 }
459 
460 } // namespace hal
NetLayoutConnectionFactory(const QList< NetLayoutPoint > &sources, const QList< NetLayoutPoint > &destinations)
void dump(const QString &stub) const
NetLayoutConnection * connection
NetLayoutPoint closestPoint(const NetLayoutPoint &pnt) const
void add(const NetLayoutConnection &other, bool atomicNet)
NetLayoutDirection operator++()
NetLayoutDirection(DirectionType dir=Undefined)
QPoint step(bool omitEndpoint=false) const
DirectionType direction() const
NetLayoutMetric(u32 id, const NetLayoutConnection *con)
bool operator<(const NetLayoutMetric &other) const
static QList< NetLayoutPoint > orderByDistance(const QList< NetLayoutPoint > &points)
bool isUndefined() const
NetLayoutPoint nextPoint(const NetLayoutDirection &dir, bool omitEndpoint=false) const
int distanceTo(const NetLayoutPoint &other) const
QGraphicsEllipseItem * graphicsFactory(float r) const
NetLayoutPoint(int x_=INT_MIN, int y_=INT_MIN)
static NetLayoutPoint fromBox(const QPoint &boxPosition, bool isInput)
NetLayoutWire(const NetLayoutPoint &p, const NetLayoutDirection &dir, bool isEnd)
QString toString() const
bool isHorizontal() const
NetLayoutPoint endPoint(WirePointType pnt) const
QGraphicsLineItem * graphicsFactory() const
bool operator==(const NetLayoutWire &other) const
uint32_t u32
Definition: defines.h:41
uint qHashPoint(const QPoint &p)
Definition: defines.h:45
uint qHash(const LaneIndex &ri)
QPointF scenePoint(const QPoint &p)
i32 id
void setPen(const QPen &pen)
void setPen(const QPen &pen)
void append(const T &value)
const T & at(int i) const const
int size() const const
T & value() const const
QMap::iterator begin()
QMap::iterator end()
QMap::iterator erase(QMap::iterator pos)
QMap::iterator insert(const Key &key, const T &value)
QList< T > values() const const
typename QMap< Key, T >::iterator insert(const Key &key, const T &value)
int x() const const
int y() const const
qreal x() const const
qreal y() const const
bool contains(const T &value) const const
QSet::iterator insert(const T &value)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const