4#include "moc_CircuitDiagram.cpp"
5#include "ui_CircuitDiagram.h"
16 size_t CurrentNodeIndex = 0;
17 std::unordered_map<size_t, size_t> Links;
18 for (
size_t i = 0; i < Nodes.size(); ++i)
19 for (
size_t j = 0; j < Nodes[i]->LinkedParams.size(); ++j)
20 for (
size_t k = 0; k < Nodes[i]->LinkedParams[j].LinkedItems.size(); ++k)
22 const auto LinkedItem = Nodes[i]->LinkedParams[j].LinkedItems[k].Item;
27 auto LinkedIt = std::find(LinkedNodes.cbegin(), LinkedNodes.cend(), LinkedItem);
28 if (LinkedIt == LinkedNodes.cend())
32 Links[CurrentNodeIndex++] = LinkedIt - LinkedNodes.cbegin();
35 double LinkedIndex =
static_cast<double>(LinkedIt - LinkedNodes.cbegin());
36 double CurrentIndex =
static_cast<double>(i);
37 Energy += std::abs(LinkedIndex - CurrentIndex);
41 for (
const auto& A : Links)
42 for (
const auto& B : Links)
43 if (B.first > A.first && A.second > B.second)
60 return *
this == Other ? 0.0 : 1.0;
73 for (
auto& LinkedParam : ObjectLinkParams)
75 const auto LinkedIDs = LinkedParam.get().GetLinkedIDs();
76 decltype(LinkedParamType::LinkedItems) Items;
81 std::transform(LinkedIDs.cbegin(), LinkedIDs.cend(), std::inserter(Items, Items.begin()),
87 std::transform(LinkedIDs.cbegin(), LinkedIDs.cend(), std::inserter(Items, Items.begin()),
92 Items.emplace_back(
nullptr);
94 LinkedParams.emplace_back(LinkedParam.get().GetLinkTitle(), std::move(Items));
100 return std::accumulate(LinkedParams.cbegin(), LinkedParams.cend(),
static_cast<size_t>(0), [](
size_t Count,
const LinkedParamType& Param) {
101 return Count + Param.LinkedItems.size();
109 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint),
122 addAction(
ui->action_Zoom_in);
123 addAction(
ui->action_Zoom_out);
124 addAction(
ui->action_Zoom_reset);
125 addAction(
ui->action_Save_Image);
182 QGraphicsItem* Item =
ui->GVCircuit->itemAt(Event->pos());
193 if (Event->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier))
195 if (Event->angleDelta().y() < 0)
197 if (Event->angleDelta().y() > 0)
201 QDialog::wheelEvent(Event);
206 QLinearGradient Gradient(0, 0, 0, 1);
207 Gradient.setCoordinateMode(QGradient::ObjectMode);
208 Gradient.setColorAt(0, Qt::lightGray);
209 Gradient.setColorAt(.3, Qt::darkGray);
210 Gradient.setColorAt(1, Qt::darkGray);
235 const auto Params = Res->second.ResourcePointer->GetParams();
237 Node.first->second.InsertLinks(Params->GetObjectLinkParams(), DynExpCore, &
HardwareAdapterNodes,
nullptr);
239 auto NetworkAddressPtr = Params->GetNetworkAddressParams();
240 if (NetworkAddressPtr)
241 Node.first->second.NetworkAddress = QString::fromStdString(NetworkAddressPtr->MakeAddress());
246 const auto Params = Res->second.ResourcePointer->GetParams();
250 auto NetworkAddressPtr = Params->GetNetworkAddressParams();
251 if (NetworkAddressPtr)
252 Node.first->second.NetworkAddress = QString::fromStdString(NetworkAddressPtr->MakeAddress());
261 const auto ValuePtrGetter = [](
auto& Pair) {
return &Pair.second; };
267 return a && b && !a->
Empty && !b->Empty?
273 std::sort(Graph.
Modules.begin(), Graph.
Modules.end(), CircuitDiagramItemSorter);
279 const auto PositionCalculator = [](
CircuitDiagramItem* Item,
const qreal x, qreal& y) {
287 qreal HardwareAdapterCurrentY = 0;
289 PositionCalculator(Item, 0, HardwareAdapterCurrentY);
290 qreal InstrumentCurrentY = 0;
293 qreal ModuleCurrentY = 0;
294 for (
const auto Item : Graph.
Modules)
298 if (HardwareAdapterCurrentY > InstrumentCurrentY && HardwareAdapterCurrentY > ModuleCurrentY)
301 Item->
TopLeftPos += { 0, (HardwareAdapterCurrentY - InstrumentCurrentY) / 2 };
302 for (
const auto Item : Graph.
Modules)
303 Item->
TopLeftPos += { 0, (HardwareAdapterCurrentY - ModuleCurrentY) / 2 };
305 else if (InstrumentCurrentY > HardwareAdapterCurrentY && InstrumentCurrentY > ModuleCurrentY)
307 for (
const auto Item : Graph.HardwareAdapters)
308 Item->TopLeftPos += { 0, (InstrumentCurrentY - HardwareAdapterCurrentY) / 2 };
309 for (
const auto Item : Graph.Modules)
310 Item->TopLeftPos += { 0, (InstrumentCurrentY - ModuleCurrentY) / 2 };
314 for (
const auto Item : Graph.HardwareAdapters)
315 Item->TopLeftPos += { 0, (ModuleCurrentY - HardwareAdapterCurrentY) / 2 };
316 for (
const auto Item : Graph.Instruments)
317 Item->TopLeftPos += { 0, (ModuleCurrentY - InstrumentCurrentY) / 2 };
323 auto Rnd = std::unique_ptr<gsl_rng,
decltype([](gsl_rng* p) { gsl_rng_free(p); })>(gsl_rng_alloc(gsl_rng_mt19937));
326 gsl_rng_set(Rnd.get(), 1);
328 gsl_siman_params_t SimAnParams;
329 SimAnParams.n_tries = 1;
330 SimAnParams.iters_fixed_T = 3;
331 SimAnParams.step_size = 1.0;
333 SimAnParams.t_initial = 10;
334 SimAnParams.mu_t = 1.05;
335 SimAnParams.t_min = 1.0e-6;
337 const auto StepFunc = [](
const gsl_rng* Rnd,
void* Element,
double StepSize) {
338 auto Graph =
static_cast<GraphType*
>(Element);
342 const auto NodeListToModifyIndex = gsl_rng_uniform_int(Rnd, 3);
343 switch (NodeListToModifyIndex)
352 NodeListToModify = &Graph->
Modules;
355 if (NodeListToModify->size() < 2)
359 const auto MaxIndexPlusOne =
static_cast<unsigned long>(std::min(
static_cast<size_t>(std::numeric_limits<unsigned long>::max()), NodeListToModify->size()));
360 const auto SrcIndex = gsl_rng_uniform_int(Rnd, MaxIndexPlusOne);
361 const auto DestIndex = gsl_rng_uniform_int(Rnd, MaxIndexPlusOne);
363 if (SrcIndex != DestIndex)
365 auto OldNode = NodeListToModify->at(DestIndex);
366 NodeListToModify->at(DestIndex) = NodeListToModify->at(SrcIndex);
367 NodeListToModify->at(SrcIndex) = OldNode;
374 gsl_siman_solve(Rnd.get(),
static_cast<void*
>(StartSample),
375 [](
void* Element) { return static_cast<GraphType*>(Element)->EvaluateEnergy(); },
377 [](
void* a,
void* b) { return static_cast<GraphType*>(a)->DistanceTo(*static_cast<GraphType*>(b)); },
379 [](
void* Source,
void* Dest) { *static_cast<GraphType*>(Dest) = *static_cast<GraphType*>(Source); },
380 [](
void* Source) { return static_cast<void*>(new GraphType(*static_cast<GraphType*>(Source))); },
381 [](
void* Element) { delete static_cast<GraphType*>(Element); },
384 Graph = *StartSample;
398 Scene = std::make_unique<QGraphicsScene>();
414 Scene->setSceneRect(
Scene->itemsBoundingRect());
415 ui->GVCircuit->setScene(
Scene.get());
430 Qt::BrushStyle::NoBrush);
453 Item.
StatePixmap->setFlag(QGraphicsItem::ItemIgnoresTransformations);
470 Item.
ItemPixmap->setFlag(QGraphicsItem::ItemIgnoresTransformations);
484 auto ItemLabelFont = Item.
ItemLabel->font();
485 ItemLabelFont.setBold(
true);
497 if (DrawOutputSocket)
515 Path.addPolygon(QPolygonF({
521 ParamGraphicsItem.
Label =
Scene->addSimpleText(LinkedParam.LinkTitle.data());
524 ParamGraphicsItem.
Label->setText(ParamGraphicsItem.
Label->text().remove(ParamGraphicsItem.
Label->text().length() - 6, 6) +
"...");
525 ParamGraphicsItem.
Label->setPos(ParamGraphicsItem.
Frame->boundingRect().center() + QPointF(
IconMargin, 0));
526 ParamGraphicsItem.
Label->setPos(ParamGraphicsItem.
Label->pos() - QPointF(0, ParamGraphicsItem.
Label->boundingRect().height() / 2));
527 ParamGraphicsItem.
Label->setToolTip(LinkedParam.LinkTitle.data());
528 ParamGraphicsItem.
Label->setData(Qt::ItemDataRole::UserRole, QVariant::fromValue(Item.
TreeWidgetItem));
530 for (
size_t LinkIndex = 0; LinkIndex < LinkedParam.LinkedItems.size(); ++LinkIndex)
532 LinkedParam.LinkedItems[LinkIndex].SocketIndex = ParamGraphicsItem.
Sockets.size();
536 ParamGraphicsItem.
Sockets.back()->setToolTip(ParamGraphicsItem.
Label->text());
537 ParamGraphicsItem.
Sockets.back()->setData(Qt::ItemDataRole::UserRole, QVariant::fromValue(Item.
TreeWidgetItem));
538 ParamGraphicsItem.
Sockets.back()->setZValue(-1);
553 Item.
NetworkPixmap->setFlag(QGraphicsItem::ItemIgnoresTransformations);
562 Pen.setDashPattern({ 1.5, 1, 1.5, 1, 1.5, 1, 1.5, 1, 1.5, 1 });
563 Pen.setDashOffset(1);
578 for (
auto LinkedItem : LinkedParam.LinkedItems)
580 if (!LinkedItem.Item || !LinkedItem.Item->OutputSocket)
583 auto From = Item.
ParamGraphicsItems[LinkedParam.ParamGraphicsItemIndex].Sockets[LinkedItem.SocketIndex]->boundingRect().center();
584 auto To = LinkedItem.Item->OutputSocket->boundingRect().center();
589 { From.x() + (To.x() - From.x()) / 4 , From.y() },
590 { From.x() + (To.x() - From.x()) / 4 * 3, To.y() }, To);
594 Item.
ParamGraphicsItems[LinkedParam.ParamGraphicsItemIndex].Links.back()->setZValue(-2);
622 return ui->GVCircuit->transform().map(QPoint(Size, Size)).x();
627 const auto RescaleFunc = [
this](NodeMapType::value_type& Item) {
628 if (Item.second.StatePixmap && !Item.second.StateIcon.isNull())
630 if (Item.second.ItemPixmap && !Item.second.ItemIcon.isNull())
632 if (Item.second.NetworkPixmap && !Item.second.NetworkIcon.isNull())
657 ui->GVCircuit->resetTransform();
658 ui->GVCircuit->centerOn(
ui->GVCircuit->scene()->sceneRect().center());
685 auto Filename =
Util::PromptSaveFilePath(
this,
"Save circuit diagram",
".png",
"Portable Network Graphics image (*.png)");
686 if (Filename.isEmpty())
689 QPixmap Pixmap =
ui->GVCircuit->grab();
690 if (!Pixmap.save(Filename))
Implements a window drawing the relations between all DynExp::Object instances as a graph....
Defines DynExp's core module as an interface between the UI and DynExp objects.
Implementation of a hardware adapter to communicate text-based commands over TCP sockets.
QGraphicsPathItem * Frame
size_t GetNumLinkedItems()
QGraphicsEllipseItem * OutputSocket
QGraphicsSimpleTextItem * Label
QString NetworkAddress
String of a network address and a network port indicating whether this item connects to a network....
QGraphicsPathItem * StateFrame
QTreeWidgetItem * TreeWidgetItem
Pointer to QTreeWidgetItem listed in main window's tree view. Pointer may be dereferenced after this ...
QGraphicsSimpleTextItem * StateLabel
QGraphicsPathItem * NetworkLink
void InsertLinks(const DynExp::ParamsBase::ObjectLinkParamsType &ObjectLinkParams, const DynExp::DynExpCore &DynExpCore, NodeMapType *HardwareAdapterNodes, NodeMapType *InstrumentNodes)
QPointF TopLeftPos
Node's top left position in the diagram in painting area's coordinates.
const bool Empty
Indicates whether this item points to an existing object.
std::vector< ParamGraphicsItemsType > ParamGraphicsItems
QGraphicsPixmapItem * ItemPixmap
QGraphicsPixmapItem * NetworkPixmap
QGraphicsPixmapItem * StatePixmap
std::vector< LinkedParamType > LinkedParams
List of linked params making use of this item.
QGraphicsPathItem * ItemFrame
QGraphicsSimpleTextItem * ItemLabel
std::vector< QGraphicsEllipseItem * > Sockets
static constexpr int AdditionalHeightPerParam
static QLinearGradient GetGrayLinearGradient()
bool Redraw(const DynExp::DynExpCore &DynExpCore)
Rebuilds the complete circuit diagram.
NodeMapType HardwareAdapterNodes
static constexpr int InnerWidth
QTreeWidgetItem * SelectedTreeWidgetItem
static constexpr int StateIconSize
void UpdateItem(CircuitDiagramItem &Item)
QTreeWidgetItem * GetSelectedEntry()
static constexpr int ParamSep
void OnContextMenuRequested(QPoint Position)
static constexpr int InnerMarginTop
static constexpr double ZoomFactor
std::unordered_map< DynExp::ItemIDType, CircuitDiagramItem > NodeMapType
static constexpr int CornerRoundingRadius
static constexpr int TreeWidgetParentTypeColumn
std::unique_ptr< Ui::CircuitDiagram > ui
std::vector< typename NodeMapType::mapped_type * > NodeListType
static constexpr int NetworkIconDistance
void RenderLinks(CircuitDiagramItem &Item)
bool UpdateStates(const DynExp::DynExpCore &DynExpCore)
Updates the items' states shown in the circuit diagram displayed currently.
CircuitDiagram(QWidget *parent)
void RenderItem(CircuitDiagramItem &Item, bool DrawOutputSocket)
static constexpr int TreeWidgetItemTypeColumn
static constexpr int TreeWidgetItemStateColumn
NodeMapType InstrumentNodes
static const QColor SocketInnerColor
virtual void mouseDoubleClickEvent(QMouseEvent *Event) override
std::unique_ptr< QGraphicsScene > Scene
static constexpr int TypeIconSize
static constexpr int InnerStartHeight
static constexpr int IconMargin
static constexpr int SocketDiameter
static constexpr int NodeHSep
static constexpr int InnerMargin
static constexpr int SocketPenLineWidth
static constexpr int NodeVSep
static constexpr int TreeWidgetItemNameColumn
static const QColor SocketOuterColor
virtual void wheelEvent(QWheelEvent *Event) override
static constexpr int InnerPenLineWidth
void RefineBySimulatedAnnealing(GraphType &Graph)
void BuildTree(const DynExp::DynExpCore &DynExpCore)
static constexpr int OuterPenLineWidth
int TransformIconSize(int Size) const
static constexpr int InnerMarginBottom
DynExp's core class acts as the interface between the user interface and DynExp's internal data like ...
auto & GetInstrumentManager() noexcept
Getter for the instrument manager.
auto & GetModuleManager() noexcept
Getter for the module manager.
auto & GetHardwareAdapterManager() noexcept
Getter for the hardware adapter manager.
std::vector< std::reference_wrapper< LinkBase > > ObjectLinkParamsType
Type of a list of all owned object link parameters.
void Log(const std::string &Message, const ErrorType Type=ErrorType::Info, const size_t Line=0, const std::string &Function="", const std::string &File="", const int ErrorCode=0, const std::stacktrace &Trace={}) noexcept
Logs an event from information specified manually.
const QColor blue(42, 130, 218)
EventLogger & EventLog()
This function holds a static EventLogger instance and returns a reference to it. DynExp uses only one...
QString PromptSaveFilePath(QWidget *Parent, const QString &Title, const QString &DefaultSuffix, const QString &NameFilter, const QString &InitialDirectory)
Works as PromptOpenFilePath() but asks the user to select a single file which does not need to exist.
Accumulates include statements to provide a precompiled header.
bool operator==(const GraphType &Other) const
double EvaluateEnergy() const
NodeListType HardwareAdapters
double DistanceTo(const GraphType &Other) const