PageRenderTime 72ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/src/griditems/neurogriditem.cpp

https://bitbucket.org/kulibali/neurocogling
C++ | 1411 lines | 1116 code | 219 blank | 76 comment | 175 complexity | e3ac2a95bcdb555969e87d082639989d MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1
  1. /*
  2. Neurocognitive Linguistics Lab
  3. Copyright (c) 2010,2011 Gordon Tisher
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions
  7. are met:
  8. - Redistributions of source code must retain the above copyright
  9. notice, this list of conditions and the following disclaimer.
  10. - Redistributions in binary form must reproduce the above copyright
  11. notice, this list of conditions and the following disclaimer in
  12. the documentation and/or other materials provided with the
  13. distribution.
  14. - Neither the name of the Neurocognitive Linguistics Lab nor the
  15. names of its contributors may be used to endorse or promote
  16. products derived from this software without specific prior
  17. written permission.
  18. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  21. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  22. COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  23. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  24. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  26. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  28. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29. POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. #include "neurogriditem.h"
  32. #include "../neurogui/labnetwork.h"
  33. #include "../neurogui/labscene.h"
  34. #include "../neurogui/labview.h"
  35. #include "../neurogui/labtree.h"
  36. #include "../neurogui/mainwindow.h"
  37. #include "../neurogui/narrow/neurolinkitem.h"
  38. #include "gridedgeitem.h"
  39. #include "multigridioitem.h"
  40. #include <QtAlgorithms>
  41. #include <cmath>
  42. #include <cfloat>
  43. using namespace NeuroGui;
  44. namespace GridItems
  45. {
  46. const QString & VERSION()
  47. {
  48. static const QString
  49. #include "../version.txt"
  50. ;
  51. return VERSION;
  52. }
  53. NEUROITEM_DEFINE_PLUGIN_CREATOR(NeuroGridItem, QString("Grid Items"), QObject::tr("Grid Item"), ":/griditems/icons/grid_item.png", GridItems::VERSION())
  54. NeuroGridItem::NeuroGridItem(LabNetwork *network, const QPointF & scenePos, const CreateContext & context)
  55. : SubNetworkItem(network, scenePos, context),
  56. _horizontal_property(this, &NeuroGridItem::horizontalCols, &NeuroGridItem::setHorizontalCols, tr("Width")),
  57. _vertical_property(this, &NeuroGridItem::verticalRows, &NeuroGridItem::setVerticalRows, tr("Height")),
  58. _num_horiz(1), _num_vert(1), _connections_changed(true), _pattern_changed(true)
  59. {
  60. if (context == NeuroItem::CREATE_UI)
  61. {
  62. const int width = NODE_WIDTH*4;
  63. const int height = NODE_WIDTH*2;
  64. const int left = -width/2;
  65. const int top = -height/2;
  66. setRect(QRectF(left, top, width, height));
  67. setLabelPos(QPointF(rect().left() + rect().width() + 5, 0));
  68. treeNode()->setLabel(tr("Grid Item %1").arg(treeNode()->id()));
  69. }
  70. connect(MainWindow::instance(), SIGNAL(itemCreated(NeuroItem*)), this, SLOT(itemChanged(NeuroItem*)));
  71. connect(MainWindow::instance(), SIGNAL(itemChanged(NeuroItem*)), this, SLOT(itemChanged(NeuroItem*)));
  72. connect(MainWindow::instance(), SIGNAL(itemDeleted(NeuroItem*)), this, SLOT(itemChanged(NeuroItem*)));
  73. connect(network, SIGNAL(stepClicked()), this, SLOT(networkStepClicked()));
  74. connect(network, SIGNAL(postStep()), this, SLOT(networkPostStep()));
  75. connect(network, SIGNAL(stepFinished()), this, SLOT(networkStepFinished()));
  76. connect(&_horizontal_property, SIGNAL(valueInBrowserChanged()), this, SLOT(propertyChanged()));
  77. connect(&_vertical_property, SIGNAL(valueInBrowserChanged()), this, SLOT(propertyChanged()));
  78. }
  79. NeuroGridItem::~NeuroGridItem()
  80. {
  81. }
  82. void NeuroGridItem::makeSubNetwork()
  83. {
  84. SubNetworkItem::makeSubNetwork();
  85. resizeScene();
  86. }
  87. void NeuroGridItem::itemChanged(NeuroItem *item)
  88. {
  89. if (item && item->scene() && this->treeNode() && (item == this || item->scene() == this->treeNode()->scene()))
  90. _pattern_changed = true;
  91. }
  92. void NeuroGridItem::propertyChanged()
  93. {
  94. _pattern_changed = true;
  95. }
  96. void NeuroGridItem::networkStepClicked()
  97. {
  98. generateGrid();
  99. }
  100. void NeuroGridItem::networkPostStep()
  101. {
  102. }
  103. void NeuroGridItem::networkStepFinished()
  104. {
  105. // this gets set by networkChanged(), but since we've just finished a step,
  106. // we don't want to re-generate the grid unless something else changes
  107. _pattern_changed = false;
  108. _connections_changed = false;
  109. #ifdef DEBUG
  110. // dump graph
  111. {
  112. QFile file("neuronet_after_step.gv");
  113. if (file.open(QIODevice::WriteOnly))
  114. {
  115. QTextStream ts(&file);
  116. network()->neuronet()->dumpGraph(ts, true);
  117. }
  118. }
  119. #endif
  120. }
  121. void NeuroGridItem::copyColors()
  122. {
  123. // copy colors
  124. foreach (Index cell_index, _all_grid_cells)
  125. {
  126. if (_gl_line_colors.contains(cell_index))
  127. {
  128. int color_index = _gl_line_colors[cell_index];
  129. NeuroLib::NeuroNet::ASYNC_STATE *cell = getCell(cell_index);
  130. if (cell && color_index < _gl_line_color_array.size())
  131. {
  132. qreal t = qBound(0.0f, cell->current().outputValue(), 1.0f);
  133. QColor color = lerp(NORMAL_LINE_COLOR, ACTIVE_COLOR, t);
  134. // two vertices for lines
  135. _gl_line_color_array[color_index++] = color.redF();
  136. _gl_line_color_array[color_index++] = color.greenF();
  137. _gl_line_color_array[color_index++] = color.blueF();
  138. _gl_line_color_array[color_index++] = color.redF();
  139. _gl_line_color_array[color_index++] = color.greenF();
  140. _gl_line_color_array[color_index++] = color.blueF();
  141. }
  142. }
  143. else if (_gl_point_colors.contains(cell_index))
  144. {
  145. int color_index = _gl_point_colors[cell_index];
  146. NeuroLib::NeuroNet::ASYNC_STATE *cell = getCell(cell_index);
  147. if (cell && color_index < _gl_point_color_array.size())
  148. {
  149. qreal t = qBound(0.0f, cell->current().outputValue(), 1.0f);
  150. QColor color = lerp(NORMAL_LINE_COLOR, ACTIVE_COLOR, t);
  151. // two vertices for lines
  152. _gl_point_color_array[color_index++] = color.redF();
  153. _gl_point_color_array[color_index++] = color.greenF();
  154. _gl_point_color_array[color_index++] = color.blueF();
  155. }
  156. }
  157. }
  158. }
  159. void NeuroGridItem::resizeScene()
  160. {
  161. LabView *view = network()->view();
  162. Q_ASSERT(view);
  163. QRect viewRect = view->viewport()->rect();
  164. QPointF topLeft = view->mapToScene(viewRect.topLeft());
  165. QPointF bottomRight = view->mapToScene(viewRect.bottomRight());
  166. QRect newSceneRect(topLeft.toPoint(), bottomRight.toPoint());
  167. treeNode()->scene()->setSceneRect(newSceneRect);
  168. emit gridChanged();
  169. }
  170. QList<NeuroGridItem::Index> NeuroGridItem::getIncomingCellsFor(const NeuroItem *item) const
  171. {
  172. NeuroNetworkItem *ni = const_cast<NeuroNetworkItem *>(dynamic_cast<const NeuroNetworkItem *>(item));
  173. if (_top_connections.contains(ni))
  174. return _top_incoming;
  175. else if (_bottom_connections.contains(ni))
  176. return _bot_incoming;
  177. return QList<Index>();
  178. }
  179. QList<NeuroGridItem::Index> NeuroGridItem::getOutgoingCellsFor(const NeuroItem *item) const
  180. {
  181. NeuroNetworkItem *ni = const_cast<NeuroNetworkItem *>(dynamic_cast<const NeuroNetworkItem *>(item));
  182. if (_top_connections.contains(ni))
  183. return _top_outgoing;
  184. else if (_bottom_connections.contains(ni))
  185. return _bot_outgoing;
  186. return QList<Index>();
  187. }
  188. void NeuroGridItem::addEdges(NeuroItem *)
  189. {
  190. // we need to adjust ALL items, not just this one!
  191. removeAllEdges();
  192. addAllEdges(0);
  193. }
  194. void NeuroGridItem::removeEdges(NeuroItem *item)
  195. {
  196. // we need to adjust ALL edges!
  197. removeAllEdges();
  198. addAllEdges(item);
  199. }
  200. struct ItemLessThan
  201. {
  202. NeuroItem *_targetItem;
  203. ItemLessThan(NeuroItem *targetItem)
  204. : _targetItem(targetItem)
  205. {
  206. }
  207. bool operator() (const NeuroItem *a, const NeuroItem *b)
  208. {
  209. int ax = a->scenePos().x();
  210. const MixinArrow *la = dynamic_cast<const MixinArrow *>(a);
  211. if (la)
  212. {
  213. if (_targetItem && la->frontLinkTarget() == _targetItem)
  214. ax = la->line().p2().x();
  215. else if (_targetItem && la->backLinkTarget() == _targetItem)
  216. ax = la->line().p1().x();
  217. }
  218. int bx = b->scenePos().x();
  219. const MixinArrow *lb = dynamic_cast<const MixinArrow *>(b);
  220. if (lb)
  221. {
  222. if (_targetItem && lb->frontLinkTarget() == _targetItem)
  223. bx = lb->line().p2().x();
  224. else if (_targetItem && lb->backLinkTarget() == _targetItem)
  225. bx = lb->line().p1().x();
  226. }
  227. return ax < bx;
  228. }
  229. };
  230. static void connect_cell_groups(NeuroLib::NeuroNet *neuronet, const QList<NeuroNetworkItem::Index> & outgoing, const QList<NeuroNetworkItem::Index> & incoming)
  231. {
  232. const int num_groups = qMin(outgoing.size(), incoming.size());
  233. if (num_groups < 1)
  234. return;
  235. const int out_step = outgoing.size() / num_groups;
  236. const int in_step = incoming.size() / num_groups;
  237. for (int i = 0; i < num_groups; ++i)
  238. {
  239. for (int j = 0; j < out_step; ++j)
  240. {
  241. for (int k = 0; k < in_step; ++k)
  242. {
  243. int out_index = i * out_step + j;
  244. int in_index = i * in_step + k;
  245. if (out_index < outgoing.size() && in_index < incoming.size())
  246. neuronet->addEdge(incoming[in_index], outgoing[out_index]);
  247. }
  248. }
  249. }
  250. }
  251. void NeuroGridItem::addAllEdges(NeuroItem *except)
  252. {
  253. Q_ASSERT(network());
  254. Q_ASSERT(network()->neuronet());
  255. NeuroLib::NeuroNet *neuronet = network()->neuronet();
  256. if (connections().size() == 0)
  257. return;
  258. // get connections and sort by X coordinate
  259. QList<NeuroNetworkItem *> top_connected, bottom_connected;
  260. foreach (NeuroItem *item, connections())
  261. {
  262. if (item != except)
  263. {
  264. NeuroNetworkItem *ni = dynamic_cast<NeuroNetworkItem *>(item);
  265. if (_top_connections.contains(ni))
  266. top_connected.append(ni);
  267. else if (_bottom_connections.contains(ni))
  268. bottom_connected.append(ni);
  269. }
  270. }
  271. qSort(top_connected.begin(), top_connected.end(), ItemLessThan(this));
  272. qSort(bottom_connected.begin(), bottom_connected.end(), ItemLessThan(this));
  273. // get top cells
  274. QList<Index> top_incoming, top_outgoing;
  275. foreach (NeuroNetworkItem *ni, top_connected)
  276. {
  277. top_incoming.append(ni->getIncomingCellsFor(this));
  278. top_outgoing.append(ni->getOutgoingCellsFor(this));
  279. }
  280. connect_cell_groups(neuronet, this->_top_outgoing, top_incoming);
  281. connect_cell_groups(neuronet, top_outgoing, this->_top_incoming);
  282. // get bottom cells
  283. QList<Index> bottom_incoming, bottom_outgoing;
  284. foreach (NeuroNetworkItem *ni, bottom_connected)
  285. {
  286. bottom_incoming.append(ni->getIncomingCellsFor(this));
  287. bottom_outgoing.append(ni->getOutgoingCellsFor(this));
  288. }
  289. connect_cell_groups(neuronet, this->_bot_outgoing, bottom_incoming);
  290. connect_cell_groups(neuronet, bottom_outgoing, this->_bot_incoming);
  291. }
  292. void NeuroGridItem::removeAllEdges()
  293. {
  294. Q_ASSERT(network());
  295. Q_ASSERT(network()->neuronet());
  296. NeuroLib::NeuroNet *neuronet = network()->neuronet();
  297. foreach (NeuroItem *item, this->connections())
  298. {
  299. NeuroNetworkItem *ni = dynamic_cast<NeuroNetworkItem *>(item);
  300. if (ni && _edges.contains(ni))
  301. {
  302. QMap<Index, Index> & item_edges = _edges[ni];
  303. QMap<Index, Index>::const_iterator i = item_edges.constBegin(), end = item_edges.constEnd();
  304. while (i != end)
  305. {
  306. neuronet->removeEdge(i.key(), i.value());
  307. ++i;
  308. }
  309. _edges.remove(ni);
  310. }
  311. }
  312. }
  313. void NeuroGridItem::onEnterView()
  314. {
  315. resizeScene();
  316. emit gridChanged();
  317. }
  318. void NeuroGridItem::onLeaveView()
  319. {
  320. emit gridChanged();
  321. }
  322. QPointF NeuroGridItem::targetPointFor(const NeuroItem *item, bool front) const
  323. {
  324. const MixinArrow *link = dynamic_cast<const MixinArrow *>(item);
  325. const NeuroNetworkItem *ni = dynamic_cast<const NeuroNetworkItem *>(item);
  326. if (link && ni)
  327. {
  328. QPointF pos = front ? link->line().p2() : link->line().p1();
  329. if (_top_connections.contains(const_cast<NeuroNetworkItem *>(ni)))
  330. return QPointF(pos.x(), pos.y() + 20);
  331. else if (_bottom_connections.contains(const_cast<NeuroNetworkItem *>(ni)))
  332. return QPointF(pos.x(), pos.y() - 20);
  333. }
  334. return scenePos();
  335. }
  336. void NeuroGridItem::addToShape(QPainterPath & drawPath, QList<TextPathRec> & texts) const
  337. {
  338. NeuroNetworkItem::addToShape(drawPath, texts);
  339. const QRectF & r = rect();
  340. drawPath.addRect(r);
  341. const int num_vertical = 5;
  342. for (int i = 0; i < num_vertical; ++i)
  343. {
  344. int x = r.left() + (i+1)*r.width()/(num_vertical+1);
  345. drawPath.moveTo(x, r.top());
  346. drawPath.lineTo(x, r.top() + r.height());
  347. }
  348. const int num_horizontal = 3;
  349. for (int i = 0; i < num_horizontal; ++i)
  350. {
  351. int y = r.top() + (i+1)*r.height()/(num_horizontal+1);
  352. drawPath.moveTo(r.left(), y);
  353. drawPath.lineTo(r.left() + r.width(), y);
  354. }
  355. }
  356. bool NeuroGridItem::canCreateNewItem(const QString & typeName, const QPointF &) const
  357. {
  358. if (typeName.contains("ExcitoryLinkItem"))
  359. return true;
  360. if (typeName.contains("InhibitoryLinkItem"))
  361. return true;
  362. if (typeName.contains("NeuroNodeItem"))
  363. return true;
  364. if (typeName.contains("NeuroOscillatorItem"))
  365. return true;
  366. if (typeName.contains("TextItem"))
  367. return true;
  368. if (typeName.contains("GridEdgeItem"))
  369. return true;
  370. return false;
  371. }
  372. bool NeuroGridItem::canBeAttachedBy(const QPointF & pos, NeuroItem *item) const
  373. {
  374. MixinArrow *link = dynamic_cast<MixinArrow *>(item);
  375. MultiItem *mi = dynamic_cast<MultiItem *>(item);
  376. if (!link && !mi) return false;
  377. // only allow connections to the top or bottom
  378. QPointF topLeft = mapToScene(rect().topLeft());
  379. QPointF bottomRight = mapToScene(rect().bottomRight());
  380. if (pos.y() > topLeft.y() && pos.y() < bottomRight.y())
  381. return false;
  382. if (pos.y() <= topLeft.y())
  383. {
  384. foreach (NeuroNetworkItem *ni, _top_connections)
  385. {
  386. mi = dynamic_cast<MultiItem *>(ni);
  387. if (mi)
  388. return false;
  389. }
  390. }
  391. else if (pos.y() >= bottomRight.y())
  392. {
  393. foreach (NeuroNetworkItem *ni, _bottom_connections)
  394. {
  395. mi = dynamic_cast<MultiItem *>(ni);
  396. if (mi)
  397. return false;
  398. }
  399. }
  400. return true;
  401. }
  402. void NeuroGridItem::onSelected()
  403. {
  404. generateGrid();
  405. emit gridChanged();
  406. }
  407. void NeuroGridItem::onAttachedBy(NeuroItem *item)
  408. {
  409. NeuroNetworkItem::onAttachedBy(item); // we don't want any sub-connection items
  410. _connections_changed = true;
  411. NeuroNetworkItem *ni = dynamic_cast<NeuroNetworkItem *>(item);
  412. if (ni)
  413. {
  414. QPointF mousePos = network()->scene()->lastMousePos();
  415. bool top = mousePos.y() < scenePos().y();
  416. if (top)
  417. _top_connections.insert(ni);
  418. else
  419. _bottom_connections.insert(ni);
  420. MultiGridIOItem *gi = dynamic_cast<MultiGridIOItem *>(ni);
  421. if (gi)
  422. adjustIOItem(gi, top);
  423. }
  424. MixinArrow *link = dynamic_cast<MixinArrow *>(item);
  425. if (link)
  426. {
  427. MixinRemember::onAttachedBy(link);
  428. }
  429. emit gridChanged();
  430. }
  431. void NeuroGridItem::onDetach(NeuroItem *item)
  432. {
  433. _connections_changed = true;
  434. NeuroNetworkItem *ni = dynamic_cast<NeuroNetworkItem *>(item);
  435. if (ni)
  436. {
  437. _top_connections.remove(ni);
  438. _bottom_connections.remove(ni);
  439. }
  440. MixinArrow *link = dynamic_cast<MixinArrow *>(item);
  441. if (link)
  442. {
  443. MixinRemember::onDetach(link);
  444. }
  445. NeuroNetworkItem::onDetach(item); // no subconnection items
  446. emit gridChanged();
  447. }
  448. void NeuroGridItem::adjustLinks()
  449. {
  450. SubNetworkItem::adjustLinks();
  451. foreach (NeuroNetworkItem *item, _top_connections)
  452. {
  453. MultiGridIOItem *gi = dynamic_cast<MultiGridIOItem *>(item);
  454. if (gi)
  455. adjustIOItem(gi, true);
  456. }
  457. foreach (NeuroNetworkItem *item, _bottom_connections)
  458. {
  459. MultiGridIOItem *gi = dynamic_cast<MultiGridIOItem *>(item);
  460. if (gi)
  461. adjustIOItem(gi, false);
  462. }
  463. }
  464. void NeuroGridItem::adjustIOItem(MultiGridIOItem *gi, bool top)
  465. {
  466. if (top)
  467. gi->setPos(scenePos().x(), scenePos().y() - rect().height()/2 - gi->rect().height()/2);
  468. else
  469. gi->setPos(scenePos().x(), scenePos().y() + rect().height()/2 + gi->rect().height()/2);
  470. }
  471. static QMap<NeuroGridItem::Index, NeuroGridItem::Index> &
  472. get_to_copy(QVector<QMap<NeuroGridItem::Index, NeuroGridItem::Index> > & all_copies, int row, int col, int num_cols)
  473. {
  474. return all_copies[(row * num_cols) + col];
  475. }
  476. static double GL_WIDTH = 2;
  477. static double GL_HEIGHT = 3;
  478. static void set_gl_vertex(int & vertex_index, QVector<float> & vertices, QVector<float> & colors,
  479. QMap<NeuroGridItem::Index, int> & color_index,
  480. NeuroGridItem::Index cell_index, const QPointF & pt,
  481. float min_x, float max_x, float min_y, float max_y,
  482. int col, int row, int num_cols, int num_rows)
  483. {
  484. float x, y, z;
  485. float pat_x = (pt.x() - min_x) / (max_x - min_x);
  486. float pat_y = (pt.y() - min_y) / (max_y - min_y);
  487. if (num_cols > 1)
  488. {
  489. float cyl_phi = (((float)col + pat_x)/(float)num_cols) * M_PI * 2;
  490. x = ::cos(cyl_phi) * GL_WIDTH;
  491. z = -::sin(cyl_phi) * GL_WIDTH;
  492. }
  493. else
  494. {
  495. x = pat_x * GL_WIDTH - GL_WIDTH/2;
  496. z = 0;
  497. }
  498. y = GL_HEIGHT/2 - (((float)row + pat_y)/(float)num_rows) * GL_HEIGHT;
  499. if (cell_index != -1)
  500. color_index[cell_index] = vertex_index;
  501. vertices[vertex_index + 0] = x;
  502. vertices[vertex_index + 1] = y;
  503. vertices[vertex_index + 2] = z;
  504. colors[vertex_index + 0] = 0;
  505. colors[vertex_index + 1] = 0;
  506. colors[vertex_index + 2] = 0;
  507. vertex_index += 3;
  508. }
  509. static const int TOP = 0;
  510. static const int BOTTOM = 1;
  511. static const int LEFT = 2;
  512. static const int RIGHT = 3;
  513. void NeuroGridItem::generateGrid()
  514. {
  515. if (!network() || network()->loading() || !network()->neuronet() || !scene() || !treeNode() || !treeNode()->scene())
  516. return;
  517. NeuroLib::NeuroNet *neuronet = network()->neuronet();
  518. if (_pattern_changed)
  519. {
  520. MainWindow::instance()->setStatus(tr("Generating neural network grid..."));
  521. QApplication::setOverrideCursor(Qt::WaitCursor);
  522. removeAllEdges();
  523. // remove old pattern cells
  524. foreach (const Index & index, _all_grid_cells)
  525. {
  526. neuronet->removeNode(index);
  527. }
  528. _all_grid_cells.clear();
  529. // get pattern cells; map pattern cells to 2d pattern positions
  530. QVector<Index> all_pattern_cells;
  531. QVector<QMap<Index, QVector<Index> > > pattern_connections(4);
  532. QVector<Index> pattern_top_incoming, pattern_top_outgoing;
  533. QVector<Index> pattern_bot_incoming, pattern_bot_outgoing;
  534. QMap<Index, QLineF> pattern_cells_to_lines;
  535. QMap<Index, QPointF> pattern_cells_to_points;
  536. bool hasTopEdge, hasBottomEdge, hasLeftEdge, hasRightEdge;
  537. collectPatternCells(neuronet,
  538. all_pattern_cells, pattern_connections,
  539. pattern_top_incoming, pattern_top_outgoing,
  540. pattern_bot_incoming, pattern_bot_outgoing,
  541. pattern_cells_to_lines, pattern_cells_to_points,
  542. hasTopEdge, hasBottomEdge, hasLeftEdge, hasRightEdge);
  543. // get min and max coordinate extents
  544. float min_x, max_x, min_y, max_y;
  545. getMinMaxCoords(pattern_cells_to_lines, pattern_cells_to_points,
  546. min_x, max_x, min_y, max_y,
  547. hasTopEdge, hasBottomEdge, hasLeftEdge, hasRightEdge);
  548. // make enough copies of the pattern, and connect their internal edges
  549. QVector<QMap<Index, Index> > all_copies(_num_vert * _num_horiz);
  550. makeCopies(neuronet, all_pattern_cells, pattern_cells_to_lines, pattern_cells_to_points,
  551. all_copies, min_x, max_x, min_y, max_y);
  552. // connect outside edges
  553. connectCopies(neuronet, all_copies, pattern_connections,
  554. pattern_top_incoming, pattern_top_outgoing,
  555. pattern_bot_incoming, pattern_bot_outgoing);
  556. // done
  557. addAllEdges(0);
  558. _pattern_changed = false;
  559. _connections_changed = false;
  560. copyColors();
  561. QApplication::restoreOverrideCursor();
  562. MainWindow::instance()->setStatus(tr("Generated neural network grid."));
  563. emit gridChanged();
  564. #ifdef DEBUG
  565. // dump graph
  566. {
  567. QFile file("neuronet_after_gen.gv");
  568. if (file.open(QIODevice::WriteOnly))
  569. {
  570. QTextStream ts(&file);
  571. neuronet->dumpGraph(ts, true);
  572. }
  573. }
  574. #endif
  575. }
  576. else if (_connections_changed)
  577. {
  578. removeAllEdges();
  579. addAllEdges(0);
  580. _connections_changed = false;
  581. }
  582. }
  583. void NeuroGridItem::connectCopies(NeuroLib::NeuroNet *neuronet,
  584. QVector<QMap<Index, Index> > & all_copies,
  585. QVector<QMap<Index, QVector<Index> > > & pattern_connections,
  586. QVector<Index> & pattern_top_incoming, QVector<Index> & pattern_top_outgoing,
  587. QVector<Index> & pattern_bot_incoming, QVector<Index> & pattern_bot_outgoing)
  588. {
  589. _top_incoming.clear();
  590. _top_outgoing.clear();
  591. _bot_incoming.clear();
  592. _bot_outgoing.clear();
  593. for (int row = 0; row < _num_vert; ++row)
  594. {
  595. for (int col = 0; col < _num_horiz; ++col)
  596. {
  597. int left_col = (col + _num_horiz - 1) % _num_horiz;
  598. int right_col = (col + 1) % _num_horiz;
  599. int up_row = row - 1;
  600. int down_row = row + 1;
  601. const QMap<Index, Index> & pat_to_copy = get_to_copy(all_copies, row, col, _num_horiz);
  602. // top
  603. if (row == 0)
  604. {
  605. foreach (const Index index, pattern_top_incoming)
  606. _top_incoming.append(pat_to_copy[index]);
  607. foreach (const Index index, pattern_top_outgoing)
  608. _top_outgoing.append(pat_to_copy[index]);
  609. }
  610. else
  611. {
  612. const QMap<Index, Index> & pat_to_copy_above = get_to_copy(all_copies, up_row, col, _num_horiz);
  613. foreach (const Index pat_in, pattern_connections[TOP].keys())
  614. {
  615. const Index copy_in = pat_to_copy[pat_in];
  616. foreach (const Index pat_out, pattern_connections[TOP][pat_in])
  617. {
  618. const Index copy_out = pat_to_copy_above[pat_out];
  619. neuronet->addEdge(copy_in, copy_out);
  620. }
  621. }
  622. }
  623. // bottom
  624. if (row == _num_vert - 1)
  625. {
  626. foreach (const Index index, pattern_bot_incoming)
  627. _bot_incoming.append(pat_to_copy[index]);
  628. foreach (const Index index, pattern_bot_outgoing)
  629. _bot_outgoing.append(pat_to_copy[index]);
  630. }
  631. else
  632. {
  633. const QMap<Index, Index> & pat_to_copy_below = get_to_copy(all_copies, down_row, col, _num_horiz);
  634. foreach (const Index pat_in, pattern_connections[BOTTOM].keys())
  635. {
  636. const Index copy_in = pat_to_copy[pat_in];
  637. foreach (const Index pat_out, pattern_connections[BOTTOM][pat_in])
  638. {
  639. const Index copy_out = pat_to_copy_below[pat_out];
  640. neuronet->addEdge(copy_in, copy_out);
  641. }
  642. }
  643. }
  644. // left
  645. const QMap<Index, Index> & pat_to_copy_left = get_to_copy(all_copies, row, left_col, _num_horiz);
  646. foreach (const Index pat_in, pattern_connections[LEFT].keys())
  647. {
  648. const Index copy_in = pat_to_copy[pat_in];
  649. foreach (const Index pat_out, pattern_connections[LEFT][pat_in])
  650. {
  651. const Index copy_out = pat_to_copy_left[pat_out];
  652. neuronet->addEdge(copy_in, copy_out);
  653. }
  654. }
  655. // right
  656. const QMap<Index, Index> & pat_to_copy_right = get_to_copy(all_copies, row, right_col, _num_horiz);
  657. foreach (const Index pat_in, pattern_connections[RIGHT].keys())
  658. {
  659. const Index copy_in = pat_to_copy[pat_in];
  660. foreach (const Index pat_out, pattern_connections[RIGHT][pat_in])
  661. {
  662. const Index copy_out = pat_to_copy_right[pat_out];
  663. neuronet->addEdge(copy_in, copy_out);
  664. }
  665. }
  666. }
  667. }
  668. }
  669. void NeuroGridItem::makeCopies(NeuroLib::NeuroNet *neuronet,
  670. QVector<Index> & all_pattern_cells,
  671. QMap<Index, QLineF> & pattern_cells_to_lines,
  672. QMap<Index, QPointF> & pattern_cells_to_points,
  673. QVector<QMap<Index, Index> > & all_copies,
  674. float min_x, float max_x, float min_y, float max_y)
  675. {
  676. _gl_line_array.resize(_num_vert * _num_horiz * pattern_cells_to_lines.size() * 6);
  677. _gl_line_color_array.resize(_num_vert * _num_horiz * pattern_cells_to_lines.size() * 6);
  678. _gl_point_array.resize(_num_vert * _num_horiz * pattern_cells_to_points.size() * 3);
  679. _gl_point_color_array.resize(_num_vert * _num_horiz * pattern_cells_to_points.size() * 3);
  680. int line_index = 0;
  681. int point_index = 0;
  682. // copy cells
  683. for (int row = 0; row < _num_vert; ++row)
  684. {
  685. for (int col = 0; col < _num_horiz; ++col)
  686. {
  687. QMap<Index, Index> & pat_to_copy = get_to_copy(all_copies, row, col, _num_horiz);
  688. // copy pattern cells
  689. foreach (const Index pat_index, all_pattern_cells)
  690. {
  691. Index copy_index = neuronet->addNode((*neuronet)[pat_index].current());
  692. _all_grid_cells.insert(copy_index);
  693. pat_to_copy[pat_index] = copy_index;
  694. // add geometry info for the viewer
  695. if (pattern_cells_to_lines.contains(pat_index))
  696. {
  697. const QLineF ln = pattern_cells_to_lines[pat_index];
  698. set_gl_vertex(line_index, _gl_line_array, _gl_line_color_array,
  699. _gl_line_colors, copy_index, ln.p1(),
  700. min_x, max_x, min_y, max_y, col, row, _num_horiz, _num_vert);
  701. set_gl_vertex(line_index, _gl_line_array, _gl_line_color_array,
  702. _gl_line_colors, -1, ln.p2(),
  703. min_x, max_x, min_y, max_y, col, row, _num_horiz, _num_vert);
  704. }
  705. else if (pattern_cells_to_points.contains(pat_index))
  706. {
  707. const QPointF pt = pattern_cells_to_points[pat_index];
  708. set_gl_vertex(point_index, _gl_point_array, _gl_point_color_array,
  709. _gl_point_colors, copy_index, pt,
  710. min_x, max_x, min_y, max_y, col, row, _num_horiz, _num_vert);
  711. }
  712. }
  713. }
  714. }
  715. // now copy internal connections
  716. for (int row = 0; row < _num_vert; ++row)
  717. {
  718. for (int col = 0; col < _num_horiz; ++col)
  719. {
  720. QMap<Index, Index> & pat_to_copy = get_to_copy(all_copies, row, col, _num_horiz);
  721. foreach (const Index pat_index, all_pattern_cells)
  722. {
  723. const Index copy_index = pat_to_copy[pat_index];
  724. foreach (const Index pat_neighbor, neuronet->neighbors(pat_index))
  725. {
  726. const Index copy_neighbor = pat_to_copy[pat_neighbor];
  727. neuronet->addEdge(copy_index, copy_neighbor);
  728. }
  729. }
  730. }
  731. }
  732. }
  733. void NeuroGridItem::getMinMaxCoords(QMap<Index, QLineF> & pattern_cells_to_lines,
  734. QMap<Index, QPointF> & pattern_cells_to_points,
  735. float & min_x, float & max_x, float & min_y, float & max_y,
  736. bool & hasTopEdge, bool & hasBottomEdge, bool & hasLeftEdge, bool & hasRightEdge)
  737. {
  738. min_x = FLT_MAX;
  739. max_x = -min_x;
  740. min_y = FLT_MAX;
  741. max_y = -min_y;
  742. foreach (QLineF line, pattern_cells_to_lines)
  743. {
  744. QPointF back = line.p1();
  745. min_x = qMin(min_x, (float)back.x());
  746. max_x = qMax(max_x, (float)back.x());
  747. min_y = qMin(min_y, (float)back.y());
  748. max_y = qMax(max_y, (float)back.y());
  749. QPointF front = line.p2();
  750. min_x = qMin(min_x, (float)front.x());
  751. max_x = qMax(max_x, (float)front.x());
  752. min_y = qMin(min_y, (float)front.y());
  753. max_y = qMax(max_y, (float)front.y());
  754. }
  755. foreach (QPointF pt, pattern_cells_to_points)
  756. {
  757. min_x = qMin(min_x, (float)pt.x());
  758. max_x = qMax(max_x, (float)pt.x());
  759. min_y = qMin(min_y, (float)pt.y());
  760. max_y = qMax(max_y, (float)pt.y());
  761. }
  762. if ((max_x - min_x) < 1)
  763. {
  764. max_x = min_x + 1;
  765. min_x = max_x - 2;
  766. }
  767. if ((max_y - min_y) < 1)
  768. {
  769. max_y = min_y + 1;
  770. min_y = max_y - 2;
  771. }
  772. if (!hasLeftEdge)
  773. min_x -= 20;
  774. if (!hasRightEdge)
  775. max_x += 20;
  776. if (!hasTopEdge)
  777. min_y -= 20;
  778. if (!hasBottomEdge)
  779. max_y += 20;
  780. }
  781. void NeuroGridItem::collectPatternCells(NeuroLib::NeuroNet *,
  782. QVector<Index> &all_pattern_cells,
  783. QVector<QMap<Index, QVector<Index> > > & pattern_connections,
  784. QVector<Index> &pattern_top_incoming, QVector<Index> &pattern_top_outgoing,
  785. QVector<Index> &pattern_bot_incoming, QVector<Index> &pattern_bot_outgoing,
  786. QMap<Index, QLineF> &pattern_cells_to_lines,
  787. QMap<Index, QPointF> &pattern_cells_to_points,
  788. bool &hasTopEdge, bool &hasBottomEdge,
  789. bool &hasLeftEdge, bool &hasRightEdge)
  790. {
  791. hasTopEdge = hasBottomEdge = hasLeftEdge = hasRightEdge = false;
  792. // get neuro items and sort by X coordinate
  793. QVector<NeuroItem *> pattern_items;
  794. foreach (QGraphicsItem *item, treeNode()->scene()->items())
  795. {
  796. NeuroItem *ni = dynamic_cast<NeuroItem *>(item);
  797. if (ni)
  798. pattern_items.append(ni);
  799. }
  800. qSort(pattern_items.begin(), pattern_items.end(), ItemLessThan(0));
  801. // go through items and record coordinates
  802. // for edge items, record connections and edge cells
  803. foreach (NeuroItem *item, pattern_items)
  804. {
  805. NeuroNetworkItem *ni = dynamic_cast<NeuroNetworkItem *>(item);
  806. if (!ni)
  807. continue;
  808. // record pattern positions
  809. recordPatternPositions(ni, pattern_cells_to_lines, pattern_cells_to_points);
  810. // all normal connections
  811. foreach (Index index, ni->allCells())
  812. {
  813. all_pattern_cells.append(index);
  814. }
  815. // edge connections
  816. GridEdgeItem *ei = dynamic_cast<GridEdgeItem *>(item);
  817. if (!ei)
  818. continue;
  819. QVector<Index> top_incoming, top_outgoing;
  820. QVector<Index> bot_incoming, bot_outgoing;
  821. QVector<Index> left_incoming, left_outgoing;
  822. QVector<Index> right_incoming, right_outgoing;
  823. foreach (NeuroItem *cx, ei->connections())
  824. {
  825. MixinArrow *link = dynamic_cast<MixinArrow *>(cx);
  826. if (!link)
  827. continue;
  828. QList<Index> frontward = link->getFrontwardCells();
  829. QList<Index> backward = link->getBackwardCells();
  830. bool frontConnected;
  831. if (ei->isConnectedToTop(link, frontConnected))
  832. {
  833. hasTopEdge = true;
  834. if (frontConnected)
  835. {
  836. if (frontward.size() > 0)
  837. top_outgoing.append(frontward.last());
  838. if (backward.size() > 0)
  839. top_incoming.append(backward.first());
  840. }
  841. else
  842. {
  843. if (frontward.size() > 0)
  844. top_incoming.append(frontward.first());
  845. if (backward.size() > 0)
  846. top_outgoing.append(backward.last());
  847. }
  848. }
  849. if (ei->isConnectedToBottom(link, frontConnected))
  850. {
  851. hasBottomEdge = true;
  852. if (frontConnected)
  853. {
  854. if (frontward.size() > 0)
  855. bot_outgoing.append(frontward.last());
  856. if (backward.size() > 0)
  857. bot_incoming.append(backward.first());
  858. }
  859. else
  860. {
  861. if (frontward.size() > 0)
  862. bot_incoming.append(frontward.first());
  863. if (backward.size() > 0)
  864. bot_outgoing.append(backward.last());
  865. }
  866. }
  867. if (ei->isConnectedToLeft(link, frontConnected))
  868. {
  869. hasLeftEdge = true;
  870. if (frontConnected)
  871. {
  872. if (frontward.size() > 0)
  873. left_outgoing.append(frontward.last());
  874. if (backward.size() > 0)
  875. left_incoming.append(backward.first());
  876. }
  877. else
  878. {
  879. if (frontward.size() > 0)
  880. left_incoming.append(frontward.first());
  881. if (backward.size() > 0)
  882. left_outgoing.append(backward.last());
  883. }
  884. }
  885. if (ei->isConnectedToRight(link, frontConnected))
  886. {
  887. hasRightEdge = true;
  888. if (frontConnected)
  889. {
  890. if (frontward.size() > 0)
  891. right_outgoing.append(frontward.last());
  892. if (backward.size() > 0)
  893. right_incoming.append(backward.first());
  894. }
  895. else
  896. {
  897. if (frontward.size() > 0)
  898. right_incoming.append(frontward.first());
  899. if (backward.size() > 0)
  900. right_outgoing.append(backward.last());
  901. }
  902. }
  903. } // for each connection, collect connecting cells
  904. // now connect up all connections for this edge item
  905. foreach (const Index in, top_incoming)
  906. pattern_connections[TOP][in] += bot_outgoing;
  907. foreach (const Index in, bot_incoming)
  908. pattern_connections[BOTTOM][in] += top_outgoing;
  909. foreach (const Index in, left_incoming)
  910. pattern_connections[LEFT][in] += right_outgoing;
  911. foreach (const Index in, right_incoming)
  912. pattern_connections[RIGHT][in] += left_outgoing;
  913. // add to pattern lists
  914. pattern_top_incoming += top_incoming;
  915. pattern_top_outgoing += top_outgoing;
  916. pattern_bot_incoming += bot_incoming;
  917. pattern_bot_outgoing += bot_outgoing;
  918. } // for each pattern item
  919. } // collectPatternCells()
  920. void NeuroGridItem::recordPatternPositions(NeuroNetworkItem *ni,
  921. QMap<Index, QLineF> & pattern_cells_to_lines,
  922. QMap<Index, QPointF> & pattern_cells_to_points)
  923. {
  924. MixinArrow *link = dynamic_cast<MixinArrow *>(ni);
  925. if (link)
  926. {
  927. QLineF line = link->line();
  928. QVector2D back(line.p1());
  929. QVector2D front(line.p2());
  930. QVector2D back_to_front = front - back;
  931. QVector2D front_to_back = back - front;
  932. QList<Index> frontwardCells = link->getFrontwardCells();
  933. int i = 0;
  934. double num_cells = frontwardCells.size();
  935. foreach (Index index, frontwardCells)
  936. {
  937. Q_ASSERT(index != -1);
  938. QVector2D start = back + back_to_front * (static_cast<double>(i) / num_cells);
  939. QVector2D end = back + back_to_front * (static_cast<double>(i+1) / num_cells);
  940. pattern_cells_to_lines[index] = QLineF(start.toPointF(), end.toPointF());
  941. ++i;
  942. }
  943. QList<Index> backwardCells = link->getBackwardCells();
  944. i = 0; num_cells = backwardCells.size();
  945. foreach (Index index, backwardCells)
  946. {
  947. Q_ASSERT(index != -1);
  948. QVector2D start = front + front_to_back * (static_cast<double>(i) / num_cells);
  949. QVector2D end = front + front_to_back * (static_cast<double>(i+1) / num_cells);
  950. pattern_cells_to_lines[index] = QLineF(start.toPointF(), end.toPointF());
  951. ++i;
  952. }
  953. }
  954. else
  955. {
  956. foreach (Index index, ni->allCells())
  957. {
  958. Q_ASSERT(index != -1);
  959. pattern_cells_to_points[index] = ni->scenePos();
  960. }
  961. }
  962. }
  963. template <typename TCollection, typename TData, typename TWrite>
  964. static void write_collection(QDataStream & ds, const TCollection & collection)
  965. {
  966. ds << static_cast<quint32>(collection.size());
  967. foreach (const TData & data, collection)
  968. {
  969. ds << static_cast<TWrite>(data);
  970. }
  971. }
  972. void NeuroGridItem::writeBinary(QDataStream &ds, const NeuroLabFileVersion &file_version) const
  973. {
  974. const_cast<NeuroGridItem *>(this)->generateGrid();
  975. SubNetworkItem::writeBinary(ds, file_version);
  976. ds << static_cast<quint32>(_num_horiz);
  977. ds << static_cast<quint32>(_num_vert);
  978. // write edges
  979. ds << static_cast<quint32>(_edges.size());
  980. QMap<NeuroNetworkItem *, QMap<Index, Index> >::const_iterator i = _edges.constBegin(), i_end = _edges.constEnd();
  981. while (i != i_end)
  982. {
  983. if (i.key())
  984. {
  985. ds << static_cast<IdType>(i.key()->id());
  986. ds << static_cast<quint32>(i.value().size());
  987. QMap<Index, Index>::const_iterator j = i.value().constBegin(), j_end = i.value().constEnd();
  988. while (j != j_end)
  989. {
  990. ds << j.key();
  991. ds << j.value();
  992. ++j;
  993. }
  994. }
  995. ++i;
  996. }
  997. // write cells and graphics
  998. write_collection<QSet<Index>, Index, quint32>(ds, _all_grid_cells);
  999. write_collection<QList<Index>, Index, quint32>(ds, _top_incoming);
  1000. write_collection<QList<Index>, Index, quint32>(ds, _top_outgoing);
  1001. write_collection<QList<Index>, Index, quint32>(ds, _bot_incoming);
  1002. write_collection<QList<Index>, Index, quint32>(ds, _bot_outgoing);
  1003. write_collection<QVector<float>, float, float>(ds, _gl_line_array);
  1004. write_collection<QVector<float>, float, float>(ds, _gl_point_array);
  1005. write_collection<QVector<float>, float, float>(ds, _gl_line_color_array);
  1006. write_collection<QVector<float>, float, float>(ds, _gl_point_color_array);
  1007. ds << static_cast<quint32>(_gl_line_colors.size());
  1008. foreach (const Index & index, _gl_line_colors.keys())
  1009. {
  1010. ds << static_cast<quint32>(index);
  1011. ds << static_cast<quint32>(_gl_line_colors[index]);
  1012. }
  1013. ds << static_cast<quint32>(_gl_point_colors.size());
  1014. foreach (const Index & index, _gl_point_colors.keys())
  1015. {
  1016. ds << static_cast<quint32>(index);
  1017. ds << static_cast<quint32>(_gl_point_colors[index]);
  1018. }
  1019. }
  1020. template <typename TCollection, typename TData, typename TRead>
  1021. static void read_collection(QDataStream & ds, TCollection & collection)
  1022. {
  1023. collection.clear();
  1024. quint32 size;
  1025. ds >> size;
  1026. for (quint32 i = 0; i < size; ++i)
  1027. {
  1028. TRead val;
  1029. ds >> val;
  1030. collection.append(static_cast<TData>(val));
  1031. }
  1032. }
  1033. void NeuroGridItem::readBinary(QDataStream &ds, const NeuroLabFileVersion &file_version)
  1034. {
  1035. SubNetworkItem::readBinary(ds, file_version);
  1036. if (file_version.neurolab_version >= NeuroGui::NEUROLAB_FILE_VERSION_9)
  1037. {
  1038. quint32 num;
  1039. ds >> num; _num_horiz = num;
  1040. ds >> num; _num_vert = num;
  1041. // read edges
  1042. _edges.clear();
  1043. if (file_version.neurolab_version >= NeuroGui::NEUROLAB_FILE_VERSION_11)
  1044. {
  1045. quint32 num_i;
  1046. ds >> num_i;
  1047. for (quint32 i = 0; i < num_i; ++i)
  1048. {
  1049. IdType id;
  1050. ds >> id;
  1051. NeuroNetworkItem *id_ptr = reinterpret_cast<NeuroNetworkItem *>(id);
  1052. QMap<Index, Index> & edge_map = _edges[id_ptr];
  1053. quint32 num_j;
  1054. ds >> num_j;
  1055. for (quint32 j = 0; j < num_j; ++j)
  1056. {
  1057. Index key, val;
  1058. ds >> key;
  1059. ds >> val;
  1060. edge_map.insert(key, val);
  1061. }
  1062. }
  1063. }
  1064. // cells and graphics
  1065. if (file_version.neurolab_version >= NeuroGui::NEUROLAB_FILE_VERSION_13)
  1066. {
  1067. _all_grid_cells.clear();
  1068. ds >> num;
  1069. for (quint32 i = 0; i < num; ++i)
  1070. {
  1071. quint32 val;
  1072. ds >> val;
  1073. _all_grid_cells.insert(static_cast<Index>(val));
  1074. }
  1075. read_collection<QList<Index>, Index, quint32>(ds, _top_incoming);
  1076. read_collection<QList<Index>, Index, quint32>(ds, _top_outgoing);
  1077. read_collection<QList<Index>, Index, quint32>(ds, _bot_incoming);
  1078. read_collection<QList<Index>, Index, quint32>(ds, _bot_outgoing);
  1079. read_collection<QVector<float>, float, float>(ds, _gl_line_array);
  1080. read_collection<QVector<float>, float, float>(ds, _gl_point_array);
  1081. read_collection<QVector<float>, float, float>(ds, _gl_line_color_array);
  1082. read_collection<QVector<float>, float, float>(ds, _gl_point_color_array);
  1083. _gl_line_colors.clear();
  1084. ds >> num;
  1085. for (quint32 i = 0; i < num; ++i)
  1086. {
  1087. quint32 index, val;
  1088. ds >> index;
  1089. ds >> val;
  1090. _gl_line_colors[static_cast<Index>(index)] = static_cast<int>(val);
  1091. }
  1092. _gl_point_colors.clear();
  1093. ds >> num;
  1094. for (quint32 i = 0; i < num; ++i)
  1095. {
  1096. quint32 index, val;
  1097. ds >> index;
  1098. ds >> val;
  1099. _gl_point_colors[static_cast<Index>(index)] = static_cast<int>(val);
  1100. }
  1101. }
  1102. }
  1103. }
  1104. void NeuroGridItem::writePointerIds(QDataStream &ds, const NeuroLabFileVersion &file_version) const
  1105. {
  1106. SubNetworkItem::writePointerIds(ds, file_version);
  1107. quint32 num = _top_connections.size();
  1108. ds << num;
  1109. foreach (const NeuroNetworkItem *ni, _top_connections)
  1110. ds << static_cast<IdType>(ni ? ni->id() : 0);
  1111. num = _bottom_connections.size();
  1112. ds << num;
  1113. foreach (const NeuroNetworkItem *ni, _bottom_connections)
  1114. ds << static_cast<IdType>(ni ? ni->id() : 0);
  1115. }
  1116. void NeuroGridItem::readPointerIds(QDataStream &ds, const NeuroLabFileVersion &file_version)
  1117. {
  1118. SubNetworkItem::readPointerIds(ds, file_version);
  1119. if (file_version.neurolab_version >= NeuroGui::NEUROLAB_FILE_VERSION_9)
  1120. {
  1121. quint32 num;
  1122. _top_connections.clear();
  1123. ds >> num;
  1124. for (quint32 i = 0; i < num; ++i)
  1125. {
  1126. IdType id;
  1127. ds >> id;
  1128. if (id) _top_connections.insert(reinterpret_cast<NeuroNetworkItem *>(id));
  1129. }
  1130. _bottom_connections.clear();
  1131. ds >> num;
  1132. for (quint32 i = 0; i < num; ++i)
  1133. {
  1134. IdType id;
  1135. ds >> id;
  1136. if (id) _bottom_connections.insert(reinterpret_cast<NeuroNetworkItem *>(id));
  1137. }
  1138. }
  1139. }
  1140. void NeuroGridItem::idsToPointers(const QMap<NeuroItem::IdType, NeuroItem *> &idMap)
  1141. {
  1142. SubNetworkItem::idsToPointers(idMap);
  1143. QSet<NeuroNetworkItem *> toAdd;
  1144. foreach (NeuroNetworkItem *ni, _top_connections)
  1145. {
  1146. IdType wanted_id = static_cast<NeuroItem::IdType>(reinterpret_cast<quint64>(ni));
  1147. NeuroNetworkItem *wanted_item = dynamic_cast<NeuroNetworkItem *>(idMap[wanted_id]);
  1148. if (wanted_item)
  1149. toAdd.insert(wanted_item);
  1150. else
  1151. throw Common::FileFormatError(tr("Dangling top connection node in file: %1").arg(static_cast<quint32>(wanted_id)));
  1152. }
  1153. _top_connections = toAdd;
  1154. toAdd.clear();
  1155. foreach (NeuroNetworkItem *ni, _bottom_connections)
  1156. {
  1157. IdType wanted_id = static_cast<NeuroItem::IdType>(reinterpret_cast<quint64>(ni));
  1158. NeuroNetworkItem *wanted_item = dynamic_cast<NeuroNetworkItem *>(idMap[wanted_id]);
  1159. if (wanted_item)
  1160. toAdd.insert(wanted_item);
  1161. else
  1162. throw Common::FileFormatError(tr("Dangling top connection node in file: %1").arg(static_cast<quint32>(wanted_id)));
  1163. }
  1164. _bottom_connections = toAdd;
  1165. // edges
  1166. QMap<NeuroNetworkItem *, QMap<Index, Index> > new_edges;
  1167. QMap<NeuroNetworkItem *, QMap<Index, Index> >::const_iterator i = _edges.constBegin(), end = _edges.constEnd();
  1168. while (i != end)
  1169. {
  1170. IdType wanted_id = static_cast<NeuroItem::IdType>(reinterpret_cast<quint64>(i.key()));
  1171. NeuroNetworkItem *wanted_item = dynamic_cast<NeuroNetworkItem *>(idMap[wanted_id]);
  1172. if (wanted_item)
  1173. new_edges[wanted_item] = i.value();
  1174. else
  1175. throw Common::FileFormatError(tr("Dangling edge node in file: %1").arg(static_cast<quint32>(wanted_id)));
  1176. ++i;
  1177. }
  1178. _edges = new_edges;
  1179. }
  1180. void NeuroGridItem::postLoad()
  1181. {
  1182. SubNetworkItem::postLoad();
  1183. // grid is generated when saving; no need to re-generate
  1184. _connections_changed = false;
  1185. _pattern_changed = false;
  1186. }
  1187. } // namespace GridItems