Skip to content

Commit

Permalink
Merge pull request #1232 from wawuwo/more-wire-forms
Browse files Browse the repository at this point in the history
Add two new wire forms
  • Loading branch information
ra3xdh authored Feb 10, 2025
2 parents a1a157b + 8f0fc38 commit c1a05d4
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 42 deletions.
3 changes: 2 additions & 1 deletion qucs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ SET(QUCS_SRCS
syntax.cpp misc.cpp messagedock.cpp
settings.cpp
imagewriter.cpp printerwriter.cpp projectView.cpp
symbolwidget.cpp
symbolwidget.cpp wire_planner.cpp
)

SET(QUCS_HDRS
Expand All @@ -170,6 +170,7 @@ symbolwidget.h
textdoc.h
wire.h
wirelabel.h
wire_planner.h
)

#
Expand Down
49 changes: 8 additions & 41 deletions qucs/mouseactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,16 +414,7 @@ void MouseActions::MMoveWire2(Schematic *Doc, QMouseEvent *Event)
Doc->setOnGrid(MAx2, MAy2);
paintAim(Doc, MAx2, MAy2); //let we paint aim cross

//because cross slightly masks a wire, let we make wire thicker
//better to make it by increasing of pen, but here we cannot access
//pen
if (MAx1 == 0) {
paintGhostLineV(Doc, MAx3, MAy3, MAy2);
paintGhostLineH(Doc, MAx3, MAy2, MAx2);
} else {
paintGhostLineH(Doc, MAx3, MAy3, MAx2);
paintGhostLineV(Doc, MAx2, MAy3, MAy2);
}
Doc->showEphemeralWire({MAx3, MAy3}, {MAx2, MAy2});

QucsMain->MouseDoubleClickAction = &MouseActions::MDoubleClickWire2;
Doc->viewport()->update();
Expand Down Expand Up @@ -1498,26 +1489,11 @@ void MouseActions::MPressWire1(Schematic *Doc, QMouseEvent *, float fX, float fY
*/
void MouseActions::MPressWire2(Schematic *Doc, QMouseEvent *Event, float fX, float fY)
{
int set1 = 0, set2 = 0;
switch (Event->button()) {
case Qt::LeftButton:
if (MAx1 == 0) { // which wire direction first ?
if (MAy2 != MAy3)
set1 = Doc->insertWire(new Wire(MAx3, MAy3, MAx3, MAy2));
if (MAx2 != MAx3) {
set2 = set1;
set1 = Doc->insertWire(new Wire(MAx3, MAy2, MAx2, MAy2));
}
} else {
if (MAx2 != MAx3)
set1 = Doc->insertWire(new Wire(MAx3, MAy3, MAx2, MAy3));
if (MAy2 != MAy3) {
set2 = set1;
set1 = Doc->insertWire(new Wire(MAx2, MAy3, MAx2, MAy2));
}
}
case Qt::LeftButton: {
auto [hasChanges, lastNode] = Doc->connectWithWire({MAx3, MAy3}, {MAx2, MAy2});

if (set1 & 2) {
if (lastNode == nullptr || lastNode->conn_count() > 1) {
// if last port is connected, then...
if (formerAction) {
// ...restore old action
Expand All @@ -1530,18 +1506,15 @@ void MouseActions::MPressWire2(Schematic *Doc, QMouseEvent *Event, float fX, flo
}
}

//ALYS: excessive update. end of function does it.
//Doc->viewport()->update();

if (set1 | set2)
if (hasChanges)
Doc->setChanged(true, true);
MAx3 = MAx2;
MAy3 = MAy2;
break;

}
/// \todo document right mouse button changes the wire corner
case Qt::RightButton:

Doc->a_wirePlanner.next();
#if 0
//ALYS - old code preserved because isn't clear - what it was???
//looks like deletion via painting.
Expand All @@ -1561,13 +1534,7 @@ void MouseActions::MPressWire2(Schematic *Doc, QMouseEvent *Event, float fX, flo
Doc->setOnGrid(MAx2, MAy2);

MAx1 ^= 1; // change the painting direction of wire corner
if (MAx1 == 0) {
paintGhostLineV(Doc, MAx3, MAy3, MAy2);
paintGhostLineH(Doc, MAx3, MAy2, MAx2);
} else {
paintGhostLineH(Doc, MAx3, MAy3, MAx2);
paintGhostLineV(Doc, MAx2, MAy3, MAy2);
}
Doc->showEphemeralWire({MAx3, MAy3}, {MAx2, MAy2});
break;

default:; // avoids compiler warnings
Expand Down
5 changes: 5 additions & 0 deletions qucs/schematic.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "diagrams/diagram.h"
#include "paintings/painting.h"
#include "components/component.h"
#include "wire_planner.h"

#include "qt3_compat/qt_compat.h"
#include "qt3_compat/q3scrollview.h"
Expand Down Expand Up @@ -431,6 +432,10 @@ protected slots:
Node* insertNode(int, int, Element*);
Node* selectedNode(int, int);

qucs_s::wire::Planner a_wirePlanner;
std::pair<bool,Node*> connectWithWire(const QPoint& a, const QPoint& b) noexcept;
void showEphemeralWire(const QPoint& a, const QPoint& b) noexcept;

int insertWireNode1(Wire*);
bool connectHWires1(Wire*);
bool connectVWires1(Wire*);
Expand Down
47 changes: 47 additions & 0 deletions qucs/schematic_element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3253,4 +3253,51 @@ void Schematic::copyPaintings(int& x1, int& y1, int& x2, int& y2,
else pp = a_Paintings->next();
}

std::pair<bool,Node*> Schematic::connectWithWire(const QPoint& a, const QPoint& b) noexcept {
auto points = a_wirePlanner.plan(a, b);

int resultFlags = 0;
// Take points by pairs
for (std::size_t i = 1; i < points.size(); i++) {
auto m = points[i-1];
auto n = points[i];
resultFlags = resultFlags | insertWire(new Wire(m.x(), m.y(), n.x(), n.y()));
}

const auto lastPoint = points.back();
for (auto* node : *a_Nodes) {
if (node->cx == lastPoint.x() && node->cy == lastPoint.y()) {
return {resultFlags, node};
}
}

// If we've got there, then the point at which the wire ended
// was optimized away. For example if there was a wire AB…
//
// A B
// o--------o
//
// And a new wire was drawn from point M to point A:
//
// M A B
// o------o--------o
//
// then two wires wouild be merged and point A would be removed:
//
// M B
// o---------------o
return {resultFlags, nullptr};
}

void Schematic::showEphemeralWire(const QPoint& a, const QPoint& b) noexcept {
auto points = a_wirePlanner.plan(a, b);
// Take points by pairs
for (std::size_t i = 1; i < points.size(); i++) {
auto m = points[i-1];
auto n = points[i];
PostPaintEvent(_Line, m.x(), m.y(), n.x(), n.y());
}

}

// vim:ts=8:sw=2:noet
107 changes: 107 additions & 0 deletions qucs/wire_planner.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include "wire_planner.h"

namespace qucs_s {
namespace wire {

inline bool is_horizontal_or_vertical(const QPoint from, const QPoint to) {
return from.x() == to.x() || from.y() == to.y();
}

// TODO: migrate to C++20 and yonger and use std::midpoint instead
int midpoint(int a, int b) {
return a + (b - a) / 2;
}


std::vector<QPoint> straight(const QPoint from, const QPoint to) {
return {from, to};
}

std::vector<QPoint> two_step_xy(const QPoint from, const QPoint to) {
if (is_horizontal_or_vertical(from, to)) {
return {from, to};
};

/*
From o---+
|
+---o To
*/
return {from, {to.x(), from.y()}, to};
}

std::vector<QPoint> two_step_yx(const QPoint from, const QPoint to) {
if (is_horizontal_or_vertical(from, to)) {
return {from, to};
};

/*
From o
|
+---o To
*/
return {from, {from.x(), to.y()}, to};
}

std::vector<QPoint> three_step_xy(const QPoint from, const QPoint to) {
if (is_horizontal_or_vertical(from, to)) {
return {from, to};
};

/*
From o---+
|
+---o To
*/
int mid_x = midpoint(from.x(), to.x());
return {from, {mid_x, from.y()}, {mid_x, to.y()}, to};
}

std::vector<QPoint> three_step_yx(const QPoint from, const QPoint to) {
if (is_horizontal_or_vertical(from, to)) {
return {from, to};
};

/*
o From
|
+---+
|
o To
*/
int mid_y = midpoint(from.y(), to.y());
return {from, {from.x(), mid_y}, {to.x(), mid_y}, to};
}


static const std::map<Planner::PlanType, Planner::RouterFunc> routers = {
{Planner::PlanType::TwoStepXY, two_step_xy},
{Planner::PlanType::TwoStepYX, two_step_yx},
{Planner::PlanType::ThreeStepXY,three_step_xy},
{Planner::PlanType::ThreeStepYX, three_step_yx}
};


Planner::Planner() : current{routers.begin()} {}

std::vector<QPoint> Planner::plan(PlanType type, const QPoint from, const QPoint to) {
return routers.at(type)(from, to);
}

std::vector<QPoint> Planner::plan(const QPoint from, const QPoint to) const {
return current->second(from, to);
}

void Planner::next() {
++current;

if (current != routers.cend()) {
return;
}

current = routers.cbegin();
}


} // namespace wire
} // namespace qucs_s
27 changes: 27 additions & 0 deletions qucs/wire_planner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef WIRE_PLANNER_H
#define WIRE_PLANNER_H

#include <QPoint>
#include <functional>
#include <map>

namespace qucs_s {
namespace wire {

class Planner {
public:
using RouterFunc = std::function<std::vector<QPoint>(QPoint, QPoint)>;
enum class PlanType { TwoStepXY, TwoStepYX, ThreeStepXY, ThreeStepYX };

Planner();
static std::vector<QPoint> plan(PlanType type, const QPoint from, const QPoint to);
std::vector<QPoint> plan(const QPoint from, const QPoint to) const;
void next();
private:
std::map<PlanType, RouterFunc>::const_iterator current;
};

} // namespace wire
} // namespace qucs_s

#endif

0 comments on commit c1a05d4

Please sign in to comment.