Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor node #845

Merged
merged 2 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions qucs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ SET(QUCS_SRCS

SET(QUCS_HDRS
element.h
conductor.h
main.h
messagedock.h
misc.h
Expand Down
17 changes: 17 additions & 0 deletions qucs/conductor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

#ifndef CONDUCTOR_H
#define CONDUCTOR_H
#include "element.h"

class WireLabel;

/** \class Conductor
* \brief label for Node and Wire classes
*
*/
class Conductor : public Element {
public:
WireLabel *Label;
};

#endif
10 changes: 5 additions & 5 deletions qucs/dialogs/sweepdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,13 @@ Graph* SweepDialog::setBiasPoints(QHash<QString,double> *NodeVals)
if(pn->Name.isEmpty()) continue;

pn->x1 = 0;
if(pn->Connections.count() < 2) {
if(pn->conn_count() < 2) {
pn->Name = ""; // no text at open nodes
continue;
}
else {
hasNoComp = true;
for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next())
for(auto *pe : *pn)
if(pe->Type == isWire) {
if( ((Wire*)pe)->isHorizontal() ) pn->x1 |= 2;
}
Expand Down Expand Up @@ -232,7 +232,7 @@ Graph* SweepDialog::setBiasPoints(QHash<QString,double> *NodeVals)
}


for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next())
for(auto pe : *pn)
if(pe->Type == isWire) {
if( ((Wire*)pe)->Port1 != pn ) // no text at next node
((Wire*)pe)->Port1->Name = "";
Expand Down Expand Up @@ -269,7 +269,7 @@ Graph* SweepDialog::setBiasPoints(QHash<QString,double> *NodeVals)
}


for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next())
for(auto pe : *pn)
if(pe->Type == isWire) {
if( ((Wire*)pe)->isHorizontal() ) pn->x1 |= 2;
}
Expand All @@ -288,7 +288,7 @@ Graph* SweepDialog::setBiasPoints(QHash<QString,double> *NodeVals)
pn->Name = misc::num2str(NodeVals->value(src_nam))+"A";
} else pn->Name = "0A";

for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next())
for(auto pe : *pn)
if(pe->Type == isWire) {
if( ((Wire*)pe)->isHorizontal() ) pn->x1 |= 2;
}
Expand Down
11 changes: 0 additions & 11 deletions qucs/element.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
#include <vector>

class Node;
class WireLabel;
class Schematic;

namespace qucs { // otherwise conflict with <windows.h>
Expand Down Expand Up @@ -207,14 +206,4 @@ class Element {
int cx, cy, x1, y1, x2, y2; // center and relative boundings
};


/** \class Conductor
* \brief label for Node and Wire classes
*
*/
class Conductor : public Element {
public:
WireLabel *Label;
};

#endif
1 change: 1 addition & 0 deletions qucs/mouseactions.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <qt3_compat/qt_compat.h>

class Wire;
class WireLabel;
class Schematic;
class Diagram;
class QPainter;
Expand Down
48 changes: 28 additions & 20 deletions qucs/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@

#include <QPainter>

Node::Node(int _x, int _y)
Node::Node(int x, int y)
{
Label = 0;
Type = isNode;
State = 0;
DType = "";

cx = _x;
cy = _y;
cx = x;
cy = y;
}

Node::~Node()
Expand All @@ -38,7 +38,7 @@ Node::~Node()
void Node::paint(QPainter* painter) const {
painter->save();

switch(Connections.count()) {
switch(connections.size()) {
case 1:
if (Label) {
painter->fillRect(cx-2, cy-2, 4, 4, Qt::darkBlue); // open but labeled
Expand All @@ -50,7 +50,7 @@ void Node::paint(QPainter* painter) const {
return;

case 2:
if (Connections.getFirst()->Type == isWire && Connections.getLast()->Type == isWire) {
if (connections.front()->Type == isWire && connections.back()->Type == isWire) {
painter->restore();
return;
}
Expand All @@ -61,31 +61,39 @@ void Node::paint(QPainter* painter) const {
painter->setBrush(Qt::darkBlue); // more than 2 connections
painter->setPen(QPen(Qt::darkBlue,1));
painter->drawEllipse(cx-3, cy-3, 6, 6);
painter->setBrush(Qt::NoBrush);
}
painter->restore();
}

// ----------------------------------------------------------------
bool Node::getSelected(int x_, int y_)
bool Node::getSelected(int x, int y)
{
if(cx-5 <= x_) if(cx+5 >= x_) if(cy-5 <= y_) if(cy+5 >= y_)
return true;

return false;
return cx - 5 <= x && x <= cx + 5 && cy - 5 <= y && y <= cy + 5;
}

// ----------------------------------------------------------------
void Node::setName(const QString& Name_, const QString& Value_, int x_, int y_)
void Node::setName(const QString& name, const QString& value, int x, int y)
{
if(Name_.isEmpty() && Value_.isEmpty()) {
if(Label) delete Label;
Label = 0;
if (name.isEmpty() && value.isEmpty()) {
if (Label) {
delete Label;
Label = nullptr;
}
return;
}

if(!Label) Label = new WireLabel(Name_, cx, cy, x_, y_, isNodeLabel);
else Label->setName(Name_);
if (!Label) {
Label = new WireLabel(name, cx, cy, x, y, isNodeLabel);
}
else {
Label->setName(name);
}
Label->pOwner = this;
Label->initValue = Value_;
Label->initValue = value;
}

Element* Node::other_than(Element* elem) const
{
auto other = std::find_if_not(connections.begin(), connections.end(), [elem](auto o){return o == elem;}
);

return other == connections.end() ? nullptr : *other;
}
88 changes: 81 additions & 7 deletions qucs/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,98 @@
#ifndef NODE_H
#define NODE_H

#include "element.h"

#include "qt3_compat/qt_compat.h"

#include "conductor.h"
#include <list>

class Node : public Conductor {
public:
Node(int, int);
Node(int x, int y);
~Node();

void paint(QPainter* painter) const;
bool getSelected(int, int);
void setName(const QString&, const QString&, int x_=0, int y_=0);
void setName(const QString&, const QString&, int x=0, int y=0);

// Add an element to the node's connections.
// No-op if element is already connected.
void connect(Element* connectable);

// Remove element from the node's connections.
void disconnect(Element* connectable);

// Tells if an element is among node's connections.
bool is_connected(Element* connectable) const;

std::size_t conn_count() const;

// Returns one of node's connections or nullptr when
// there is no connections
Element* any() const;

// Returns an element from node's connections which is
// not equal to e; nullptr if there is no such element
Element* other_than(Element* e) const;

using const_iterator = std::list<Element*>::const_iterator;
const_iterator begin() const;
const_iterator end() const;

Q3PtrList<Element> Connections;
QString Name; // node name used by creation of netlist
QString DType; // type of node (used by digital files)
int State; // remember some things during some operations

private:
// Nodes usually have quite a few connections. In ideal case, when all wire
// placement optimizations work properly, there can be at most four connections
// to a single node because Qucs-S allows only orthogonal element placement.
//
// Additions/deletions are frequent and made in random order. Considering
// all that I think the doubly-linked list is a good choice here.
//
// A node doesn't claim ownership of any connected object, storing raw pointers is OK.
//
// Long-term TODO: refactor so that node will keep only pointers to *connectable*
// objects, i.e. components and wires. Paintings, graphs, wirelabels,
// etc., are Elements too, it's just wrong to use so generic type.
std::list<Element*> connections;
};

inline void Node::connect(Element* connectable)
{
if (is_connected(connectable)) {
return;
}
connections.push_front(connectable);
}

inline void Node::disconnect(Element* connectable)
{
connections.remove(connectable);
}

inline bool Node::is_connected(Element *connectable) const
{
return std::find(connections.begin(), connections.end(), connectable) != connections.end();
}

inline std::size_t Node::conn_count() const
{
return connections.size();
}

inline Node::const_iterator Node::begin() const
{
return connections.begin();
}

inline Node::const_iterator Node::end() const
{
return connections.end();
}

inline Element* Node::any() const
{
return connections.empty() ? nullptr : connections.front();
}

#endif
8 changes: 4 additions & 4 deletions qucs/schematic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ void Schematic::paintSchToViewpainter(QPainter* painter, bool printAll) {
}

for (auto* node : *Nodes) {
for (auto* connected : node->Connections) {
for (auto* connected : *node) {
if (should_draw(connected)) {
draw_preserve_selection(node, painter);
break;
Expand Down Expand Up @@ -2133,7 +2133,7 @@ bool Schematic::elementsOnGrid()
// rescue non-selected node labels
for (Port *pp : pc->Ports)
if (pp->Connection->Label)
if (pp->Connection->Connections.count() < 2) {
if (pp->Connection->conn_count() < 2) {
LabelCache.append(pp->Connection->Label);
pp->Connection->Label->pOwner = 0;
pp->Connection->Label = 0;
Expand Down Expand Up @@ -2170,12 +2170,12 @@ bool Schematic::elementsOnGrid()
// rescue non-selected node label
pLabel = nullptr;
if (pw->Port1->Label) {
if (pw->Port1->Connections.count() < 2) {
if (pw->Port1->conn_count() < 2) {
pLabel = pw->Port1->Label;
pw->Port1->Label = nullptr;
}
} else if (pw->Port2->Label) {
if (pw->Port2->Connections.count() < 2) {
if (pw->Port2->conn_count() < 2) {
pLabel = pw->Port2->Label;
pw->Port2->Label = nullptr;
}
Expand Down
Loading
Loading