4 #include "moc_CircuitDiagram.cpp"
15 size_t CurrentNodeIndex = 0;
16 std::unordered_map<size_t, size_t> Links;
17 for (
size_t i = 0; i < Nodes.size(); ++i)
18 for (
size_t j = 0; j < Nodes[i]->LinkedParams.size(); ++j)
19 for (
size_t k = 0; k < Nodes[i]->LinkedParams[j].LinkedItems.size(); ++k)
21 const auto LinkedItem = Nodes[i]->LinkedParams[j].LinkedItems[k].Item;
26 auto LinkedIt = std::find(LinkedNodes.cbegin(), LinkedNodes.cend(), LinkedItem);
27 if (LinkedIt == LinkedNodes.cend())
31 Links[CurrentNodeIndex++] = LinkedIt - LinkedNodes.cbegin();
34 double LinkedIndex =
static_cast<double>(LinkedIt - LinkedNodes.cbegin());
35 double CurrentIndex =
static_cast<double>(i);
36 Energy += std::abs(LinkedIndex - CurrentIndex);
40 for (
const auto& A : Links)
41 for (
const auto& B : Links)
42 if (B.first > A.first && A.second > B.second)
59 return *
this == Other ? 0.0 : 1.0;
72 for (
auto& LinkedParam : ObjectLinkParams)
74 const auto LinkedIDs = LinkedParam.get().GetLinkedIDs();
75 decltype(LinkedParamType::LinkedItems) Items;
80 std::transform(LinkedIDs.cbegin(), LinkedIDs.cend(), std::inserter(Items, Items.begin()),
86 std::transform(LinkedIDs.cbegin(), LinkedIDs.cend(), std::inserter(Items, Items.begin()),
91 Items.emplace_back(
nullptr);
93 LinkedParams.emplace_back(LinkedParam.get().GetLinkTitle(), std::move(Items));
99 return std::accumulate(LinkedParams.cbegin(), LinkedParams.cend(),
static_cast<size_t>(0), [](
size_t Count,
const LinkedParamType& Param) {
100 return Count + Param.LinkedItems.size();
108 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint),
120 addAction(
ui.action_Zoom_in);
121 addAction(
ui.action_Zoom_out);
122 addAction(
ui.action_Zoom_reset);
123 addAction(
ui.action_Save_Image);
180 QGraphicsItem* Item =
ui.GVCircuit->itemAt(Event->pos());
191 if (Event->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier))
193 if (Event->angleDelta().y() < 0)
195 if (Event->angleDelta().y() > 0)
199 QDialog::wheelEvent(Event);
204 QLinearGradient Gradient(0, 0, 0, 1);
205 Gradient.setCoordinateMode(QGradient::ObjectMode);
206 Gradient.setColorAt(0, Qt::lightGray);
233 const auto Params = Res->second.ResourcePointer->GetParams();
235 Node.first->second.InsertLinks(Params->GetObjectLinkParams(), DynExpCore, &
HardwareAdapterNodes,
nullptr);
237 auto NetworkAddressPtr = Params->GetNetworkAddressParams();
238 if (NetworkAddressPtr)
239 Node.first->second.NetworkAddress = QString::fromStdString(NetworkAddressPtr->MakeAddress());
244 const auto Params = Res->second.ResourcePointer->GetParams();
248 auto NetworkAddressPtr = Params->GetNetworkAddressParams();
249 if (NetworkAddressPtr)
250 Node.first->second.NetworkAddress = QString::fromStdString(NetworkAddressPtr->MakeAddress());
259 const auto ValuePtrGetter = [](
auto& Pair) {
return &Pair.second; };
265 return a && b && !a->
Empty && !b->Empty?
271 std::sort(Graph.
Modules.begin(), Graph.
Modules.end(), CircuitDiagramItemSorter);
277 const auto PositionCalculator = [](
CircuitDiagramItem* Item,
const qreal x, qreal& y) {
285 qreal HardwareAdapterCurrentY = 0;
287 PositionCalculator(Item, 0, HardwareAdapterCurrentY);
288 qreal InstrumentCurrentY = 0;
291 qreal ModuleCurrentY = 0;
292 for (
const auto Item : Graph.
Modules)
296 if (HardwareAdapterCurrentY > InstrumentCurrentY && HardwareAdapterCurrentY > ModuleCurrentY)
299 Item->
TopLeftPos += { 0, (HardwareAdapterCurrentY - InstrumentCurrentY) / 2 };
300 for (
const auto Item : Graph.
Modules)
301 Item->
TopLeftPos += { 0, (HardwareAdapterCurrentY - ModuleCurrentY) / 2 };
303 else if (InstrumentCurrentY > HardwareAdapterCurrentY && InstrumentCurrentY > ModuleCurrentY)
306 Item->
TopLeftPos += { 0, (InstrumentCurrentY - HardwareAdapterCurrentY) / 2 };
307 for (
const auto Item : Graph.
Modules)
308 Item->
TopLeftPos += { 0, (InstrumentCurrentY - ModuleCurrentY) / 2 };
313 Item->
TopLeftPos += { 0, (ModuleCurrentY - HardwareAdapterCurrentY) / 2 };
315 Item->
TopLeftPos += { 0, (ModuleCurrentY - InstrumentCurrentY) / 2 };
321 auto Rnd = std::unique_ptr<gsl_rng, decltype([](gsl_rng* p) { gsl_rng_free(p); })>(gsl_rng_alloc(gsl_rng_mt19937));
324 gsl_rng_set(Rnd.get(), 1);
326 gsl_siman_params_t SimAnParams;
327 SimAnParams.n_tries = 1;
328 SimAnParams.iters_fixed_T = 3;
329 SimAnParams.step_size = 1.0;
331 SimAnParams.t_initial = 10;
332 SimAnParams.mu_t = 1.05;
333 SimAnParams.t_min = 1.0e-6;
335 const auto StepFunc = [](
const gsl_rng* Rnd,
void* Element,
double StepSize) {
336 auto Graph =
static_cast<GraphType*
>(Element);
340 const auto NodeListToModifyIndex = gsl_rng_uniform_int(Rnd, 3);
341 switch (NodeListToModifyIndex)
350 NodeListToModify = &Graph->
Modules;
353 if (NodeListToModify->size() < 2)
357 const auto MaxIndexPlusOne =
static_cast<unsigned long>(std::min(
static_cast<size_t>(std::numeric_limits<unsigned long>::max()), NodeListToModify->size()));
358 const auto SrcIndex = gsl_rng_uniform_int(Rnd, MaxIndexPlusOne);
359 const auto DestIndex = gsl_rng_uniform_int(Rnd, MaxIndexPlusOne);
361 if (SrcIndex != DestIndex)
363 auto OldNode = NodeListToModify->at(DestIndex);
364 NodeListToModify->at(DestIndex) = NodeListToModify->at(SrcIndex);
365 NodeListToModify->at(SrcIndex) = OldNode;
372 gsl_siman_solve(Rnd.get(),
static_cast<void*
>(StartSample),
373 [](
void* Element) { return static_cast<GraphType*>(Element)->EvaluateEnergy(); },
375 [](
void* a,
void* b) { return static_cast<GraphType*>(a)->DistanceTo(*static_cast<GraphType*>(b)); },
377 [](
void* Source,
void* Dest) { *static_cast<GraphType*>(Dest) = *static_cast<GraphType*>(Source); },
378 [](
void* Source) { return static_cast<void*>(new GraphType(*static_cast<GraphType*>(Source))); },
379 [](
void* Element) { delete static_cast<GraphType*>(Element); },
382 Graph = *StartSample;
396 Scene = std::make_unique<QGraphicsScene>();
412 Scene->setSceneRect(
Scene->itemsBoundingRect());
413 ui.GVCircuit->setScene(
Scene.get());
428 Qt::BrushStyle::NoBrush);
451 Item.
StatePixmap->setFlag(QGraphicsItem::ItemIgnoresTransformations);
468 Item.
ItemPixmap->setFlag(QGraphicsItem::ItemIgnoresTransformations);
482 auto ItemLabelFont = Item.
ItemLabel->font();
483 ItemLabelFont.setBold(
true);
495 if (DrawOutputSocket)
513 Path.addPolygon(QPolygonF({
519 ParamGraphicsItem.
Label =
Scene->addSimpleText(LinkedParam.LinkTitle.data());
522 ParamGraphicsItem.
Label->setText(ParamGraphicsItem.
Label->text().remove(ParamGraphicsItem.
Label->text().length() - 6, 6) +
"...");
523 ParamGraphicsItem.
Label->setPos(ParamGraphicsItem.
Frame->boundingRect().center() + QPointF(
IconMargin, 0));
524 ParamGraphicsItem.
Label->setPos(ParamGraphicsItem.
Label->pos() - QPointF(0, ParamGraphicsItem.
Label->boundingRect().height() / 2));
525 ParamGraphicsItem.
Label->setToolTip(LinkedParam.LinkTitle.data());
526 ParamGraphicsItem.
Label->setData(Qt::ItemDataRole::UserRole, QVariant::fromValue(Item.
TreeWidgetItem));
528 for (
size_t LinkIndex = 0; LinkIndex < LinkedParam.LinkedItems.size(); ++LinkIndex)
530 LinkedParam.LinkedItems[LinkIndex].SocketIndex = ParamGraphicsItem.
Sockets.size();
534 ParamGraphicsItem.
Sockets.back()->setToolTip(ParamGraphicsItem.
Label->text());
535 ParamGraphicsItem.
Sockets.back()->setData(Qt::ItemDataRole::UserRole, QVariant::fromValue(Item.
TreeWidgetItem));
536 ParamGraphicsItem.
Sockets.back()->setZValue(-1);
551 Item.
NetworkPixmap->setFlag(QGraphicsItem::ItemIgnoresTransformations);
560 Pen.setDashPattern({ 1.5, 1, 1.5, 1, 1.5, 1, 1.5, 1, 1.5, 1 });
561 Pen.setDashOffset(1);
576 for (
auto LinkedItem : LinkedParam.LinkedItems)
578 if (!LinkedItem.Item || !LinkedItem.Item->OutputSocket)
581 auto From = Item.
ParamGraphicsItems[LinkedParam.ParamGraphicsItemIndex].Sockets[LinkedItem.SocketIndex]->boundingRect().center();
582 auto To = LinkedItem.Item->OutputSocket->boundingRect().center();
587 { From.x() + (To.x() - From.x()) / 4 , From.y() },
588 { From.x() + (To.x() - From.x()) / 4 * 3, To.y() }, To);
591 { !LinkedItem.Item->Empty ? SocketInnerColor : Qt::red, OuterPenLineWidth }, Qt::BrushStyle::NoBrush));
592 Item.
ParamGraphicsItems[LinkedParam.ParamGraphicsItemIndex].Links.back()->setZValue(-2);
620 return ui.GVCircuit->transform().map(QPoint(Size, Size)).x();
625 const auto RescaleFunc = [
this](NodeMapType::value_type& Item) {
626 if (Item.second.StatePixmap && !Item.second.StateIcon.isNull())
628 if (Item.second.ItemPixmap && !Item.second.ItemIcon.isNull())
630 if (Item.second.NetworkPixmap && !Item.second.NetworkIcon.isNull())
655 ui.GVCircuit->resetTransform();
656 ui.GVCircuit->centerOn(
ui.GVCircuit->scene()->sceneRect().center());
683 auto Filename =
Util::PromptSaveFilePath(
this,
"Save circuit diagram",
".png",
"Portable Network Graphics image (*.png)");
684 if (Filename.isEmpty())
687 QPixmap Pixmap =
ui.GVCircuit->grab();
688 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::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 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 & GetModuleManager() noexcept
Getter for the module manager.
auto & GetHardwareAdapterManager() noexcept
Getter for the hardware adapter manager.
auto & GetInstrumentManager() noexcept
Getter for the instrument 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 darkGray(53, 53, 53)
const QColor gray(128, 128, 128)
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