mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-03-17 23:59:58 +01:00
Possibilite de modifier les conducteurs. Attention, version encore buggee.
git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@41 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
540
conducteur.cpp
540
conducteur.cpp
@@ -2,6 +2,10 @@
|
|||||||
#include "conducteur.h"
|
#include "conducteur.h"
|
||||||
#include "element.h"
|
#include "element.h"
|
||||||
|
|
||||||
|
bool Conducteur::pen_and_brush_initialized = false;
|
||||||
|
QPen Conducteur::conducer_pen = QPen();
|
||||||
|
QBrush Conducteur::conducer_brush = QBrush();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Constructeur
|
Constructeur
|
||||||
@param p1 Premiere Borne auquel le conducteur est lie
|
@param p1 Premiere Borne auquel le conducteur est lie
|
||||||
@@ -19,12 +23,20 @@ Conducteur::Conducteur(Borne *p1, Borne* p2, Element *parent, QGraphicsScene *sc
|
|||||||
// en cas d'echec de l'ajout (conducteur deja existant notamment)
|
// en cas d'echec de l'ajout (conducteur deja existant notamment)
|
||||||
if (!ajout_p1 || !ajout_p2) return;
|
if (!ajout_p1 || !ajout_p2) return;
|
||||||
destroyed = false;
|
destroyed = false;
|
||||||
// le conducteur est represente par un trait fin
|
modified_path = false;
|
||||||
QPen t;
|
// attributs de dessin par defaut (communs a tous les conducteurs)
|
||||||
t.setWidthF(1.0);
|
if (!pen_and_brush_initialized) {
|
||||||
setPen(t);
|
conducer_pen.setJoinStyle(Qt::MiterJoin);
|
||||||
|
conducer_pen.setCapStyle(Qt::SquareCap);
|
||||||
|
conducer_pen.setColor(Qt::black);
|
||||||
|
conducer_pen.setStyle(Qt::SolidLine);
|
||||||
|
conducer_pen.setWidthF(1.0);
|
||||||
|
conducer_brush.setColor(Qt::white);
|
||||||
|
conducer_brush.setStyle(Qt::NoBrush);
|
||||||
|
pen_and_brush_initialized = true;
|
||||||
|
}
|
||||||
// calcul du rendu du conducteur
|
// calcul du rendu du conducteur
|
||||||
calculeConducteur();
|
priv_calculeConducteur(borne1 -> amarrageConducteur(), borne1 -> orientation(), borne2 -> amarrageConducteur(), borne2 -> orientation());
|
||||||
setFlags(QGraphicsItem::ItemIsSelectable);
|
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,8 +44,16 @@ Conducteur::Conducteur(Borne *p1, Borne* p2, Element *parent, QGraphicsScene *sc
|
|||||||
Met a jour la representation graphique du conducteur.
|
Met a jour la representation graphique du conducteur.
|
||||||
@param rect Rectangle a mettre a jour
|
@param rect Rectangle a mettre a jour
|
||||||
*/
|
*/
|
||||||
void Conducteur::update(const QRectF &rect = QRectF()) {
|
void Conducteur::update(const QRectF &rect) {
|
||||||
calculeConducteur();
|
// utilise soit la fonction priv_modifieConducteur soit la fonction priv_calculeConducteur
|
||||||
|
void (Conducteur::* fonction_update) (const QPointF &, Borne::Orientation, const QPointF &, Borne::Orientation);
|
||||||
|
fonction_update = (points.count() && modified_path) ? &Conducteur::priv_modifieConducteur : &Conducteur::priv_calculeConducteur;
|
||||||
|
|
||||||
|
// appelle la bonne fonction pour calculer l'aspect du conducteur
|
||||||
|
(this ->* fonction_update)(
|
||||||
|
borne1 -> amarrageConducteur(), borne1 -> orientation(),
|
||||||
|
borne2 -> amarrageConducteur(), borne2 -> orientation()
|
||||||
|
);
|
||||||
QGraphicsPathItem::update(rect);
|
QGraphicsPathItem::update(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,37 +65,6 @@ void Conducteur::update(const QRectF &rect = QRectF()) {
|
|||||||
@param pos position de la borne b
|
@param pos position de la borne b
|
||||||
*/
|
*/
|
||||||
void Conducteur::updateWithNewPos(const QRectF &rect, const Borne *b, const QPointF &newpos) {
|
void Conducteur::updateWithNewPos(const QRectF &rect, const Borne *b, const QPointF &newpos) {
|
||||||
calculeConducteurWithNewPos(b, newpos);
|
|
||||||
QGraphicsPathItem::update(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Met a jour la representation graphique du conducteur.
|
|
||||||
@param x abscisse du rectangle a mettre a jour
|
|
||||||
@param y ordonnee du rectangle a mettre a jour
|
|
||||||
@param width longueur du rectangle a mettre a jour
|
|
||||||
@param height hauteur du rectangle a mettre a jour
|
|
||||||
*/
|
|
||||||
void Conducteur::update(qreal x, qreal y, qreal width, qreal height) {
|
|
||||||
calculeConducteur();
|
|
||||||
QGraphicsPathItem::update(x, y, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Met a jour le QPainterPath constituant le conducteur pour obtenir
|
|
||||||
un conducteur uniquement compose de droites reliant les deux bornes.
|
|
||||||
*/
|
|
||||||
void Conducteur::calculeConducteur() {
|
|
||||||
QPointF p1 = borne1 -> amarrageConducteur();
|
|
||||||
QPointF p2 = borne2 -> amarrageConducteur();
|
|
||||||
priv_calculeConducteur(p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Met a jour le QPainterPath constituant le conducteur pour obtenir
|
|
||||||
un conducteur uniquement compose de droites reliant les deux bornes.
|
|
||||||
*/
|
|
||||||
void Conducteur::calculeConducteurWithNewPos(const Borne *b, const QPointF &newpos) {
|
|
||||||
QPointF p1, p2;
|
QPointF p1, p2;
|
||||||
if (b == borne1) {
|
if (b == borne1) {
|
||||||
p1 = newpos;
|
p1 = newpos;
|
||||||
@@ -87,86 +76,116 @@ void Conducteur::calculeConducteurWithNewPos(const Borne *b, const QPointF &newp
|
|||||||
p1 = borne1 -> amarrageConducteur();
|
p1 = borne1 -> amarrageConducteur();
|
||||||
p2 = borne2 -> amarrageConducteur();
|
p2 = borne2 -> amarrageConducteur();
|
||||||
}
|
}
|
||||||
priv_calculeConducteur(p1, p2);
|
if (points.count() && modified_path)
|
||||||
|
priv_modifieConducteur(p1, borne1 -> orientation(), p2, borne2 -> orientation());
|
||||||
|
else
|
||||||
|
priv_calculeConducteur(p1, borne1 -> orientation(), p2, borne2 -> orientation());
|
||||||
|
QGraphicsPathItem::update(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@param p1 Coordonnees du point d'amarrage de la borne 1
|
Genere le QPainterPath a partir de la liste des points
|
||||||
@param p2 Coordonnees du point d'amarrage de la borne 2
|
|
||||||
*/
|
*/
|
||||||
void Conducteur::priv_calculeConducteur(const QPointF &p1, const QPointF &p2) {
|
void Conducteur::pointsToPath() {
|
||||||
QPainterPath t;
|
QPainterPath path;
|
||||||
|
bool moveto_done = false;
|
||||||
|
foreach(QPointF point, points) {
|
||||||
|
if (!moveto_done) {
|
||||||
|
path.moveTo(point);
|
||||||
|
moveto_done = true;
|
||||||
|
} else path.lineTo(point);
|
||||||
|
}
|
||||||
|
setPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Gere les updates
|
||||||
|
@param p1 Coordonnees du point d'amarrage de la borne 1
|
||||||
|
@param o1 Orientation de la borne 1
|
||||||
|
@param p2 Coordonnees du point d'amarrage de la borne 2
|
||||||
|
@param o2 Orientation de la borne 2
|
||||||
|
*/
|
||||||
|
void Conducteur::priv_modifieConducteur(const QPointF &p1, Borne::Orientation, const QPointF &p2, Borne::Orientation) {
|
||||||
|
Q_ASSERT_X(points.count() > 1, "priv_modifieConducteur", "pas de points a modifier");
|
||||||
|
|
||||||
|
// recupere les dernieres coordonnees connues des bornes
|
||||||
|
QPointF old_p1 = mapFromScene(borne1 -> amarrageConducteur());
|
||||||
|
QPointF old_p2 = mapFromScene(borne2 -> amarrageConducteur());
|
||||||
|
|
||||||
|
// recupere les coordonnees fournies des bornes
|
||||||
|
QPointF new_p1 = mapFromScene(p1);
|
||||||
|
QPointF new_p2 = mapFromScene(p2);
|
||||||
|
|
||||||
|
// les distances horizontales et verticales entre les anciennes bornes
|
||||||
|
// sont stockees dans orig_dist_2_terms_x et orig_dist_2_terms_y
|
||||||
|
|
||||||
|
// calcule les distances horizontales et verticales entre les nouvelles bornes
|
||||||
|
qreal new_dist_2_bornes_x = new_p2.x() - new_p1.x();
|
||||||
|
qreal new_dist_2_bornes_y = new_p2.y() - new_p1.y();
|
||||||
|
|
||||||
|
// en deduit les coefficients de "redimensionnement"
|
||||||
|
qreal coeff_x = new_dist_2_bornes_x / orig_dist_2_terms_x;
|
||||||
|
qreal coeff_y = new_dist_2_bornes_y / orig_dist_2_terms_y;
|
||||||
|
|
||||||
|
// genere les nouveaux points
|
||||||
|
int limite = moves_x.size() - 1;
|
||||||
|
int coeff = type_trajet_x ? 1 : -1;
|
||||||
|
points.clear();
|
||||||
|
points << (type_trajet_x ? new_p1 : new_p2);
|
||||||
|
for (int i = 0 ; i < limite ; ++ i) {
|
||||||
|
QPointF previous_point = points.last();
|
||||||
|
points << QPointF (
|
||||||
|
previous_point.x() + (moves_x.at(i) * coeff_x * coeff),
|
||||||
|
previous_point.y() + (moves_y.at(i) * coeff_y * coeff)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
points << (type_trajet_x ? new_p2 : new_p1);
|
||||||
|
|
||||||
|
pointsToPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Calcule un trajet "par defaut" pour le conducteur
|
||||||
|
@param p1 Coordonnees du point d'amarrage de la borne 1
|
||||||
|
@param o1 Orientation de la borne 1
|
||||||
|
@param p2 Coordonnees du point d'amarrage de la borne 2
|
||||||
|
@param o2 Orientation de la borne 2
|
||||||
|
*/
|
||||||
|
void Conducteur::priv_calculeConducteur(const QPointF &p1, Borne::Orientation o1, const QPointF &p2, Borne::Orientation o2) {
|
||||||
QPointF sp1, sp2, depart, newp1, newp2, arrivee, depart0, arrivee0;
|
QPointF sp1, sp2, depart, newp1, newp2, arrivee, depart0, arrivee0;
|
||||||
Borne::Orientation ori_borne1, ori_borne2, ori_depart, ori_arrivee;
|
Borne::Orientation ori_depart, ori_arrivee;
|
||||||
|
points.clear();
|
||||||
// recupere les orientations des bornes
|
type_trajet_x = p1.x() < p2.x();
|
||||||
ori_borne1 = borne1 -> orientation();
|
|
||||||
ori_borne2 = borne2 -> orientation();
|
|
||||||
|
|
||||||
// mappe les points par rapport a la scene
|
// mappe les points par rapport a la scene
|
||||||
sp1 = mapFromScene(p1);
|
sp1 = mapFromScene(p1);
|
||||||
sp2 = mapFromScene(p2);
|
sp2 = mapFromScene(p2);
|
||||||
|
|
||||||
// tailles des prolongements
|
// prolonge les bornes
|
||||||
qreal first_seg_size = 10;
|
newp1 = extendTerminal(sp1, o1);
|
||||||
qreal last_seg_size = 10;
|
newp2 = extendTerminal(sp2, o2);
|
||||||
|
|
||||||
// prolonge la borne 1
|
// distingue le depart de l'arrivee : le trajet se fait toujours de gauche a droite (apres prolongation)
|
||||||
switch(ori_borne1) {
|
|
||||||
case Borne::Nord:
|
|
||||||
newp1 = QPointF(sp1.x(), sp1.y() - first_seg_size);
|
|
||||||
break;
|
|
||||||
case Borne::Est:
|
|
||||||
newp1 = QPointF(sp1.x() + first_seg_size, sp1.y());
|
|
||||||
break;
|
|
||||||
case Borne::Sud:
|
|
||||||
newp1 = QPointF(sp1.x(), sp1.y() + first_seg_size);
|
|
||||||
break;
|
|
||||||
case Borne::Ouest:
|
|
||||||
newp1 = QPointF(sp1.x() - first_seg_size, sp1.y());
|
|
||||||
break;
|
|
||||||
default: newp1 = sp1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prolonge la borne 2
|
|
||||||
switch(ori_borne2) {
|
|
||||||
case Borne::Nord:
|
|
||||||
newp2 = QPointF(sp2.x(), sp2.y() - last_seg_size);
|
|
||||||
break;
|
|
||||||
case Borne::Est:
|
|
||||||
newp2 = QPointF(sp2.x() + last_seg_size, sp2.y());
|
|
||||||
break;
|
|
||||||
case Borne::Sud:
|
|
||||||
newp2 = QPointF(sp2.x(), sp2.y() + last_seg_size);
|
|
||||||
break;
|
|
||||||
case Borne::Ouest:
|
|
||||||
newp2 = QPointF(sp2.x() - last_seg_size, sp2.y());
|
|
||||||
break;
|
|
||||||
default: newp2 = sp2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// distingue le depart de l'arrivee : le trajet se fait toujours de gauche a droite
|
|
||||||
if (newp1.x() <= newp2.x()) {
|
if (newp1.x() <= newp2.x()) {
|
||||||
depart = newp1;
|
depart = newp1;
|
||||||
arrivee = newp2;
|
arrivee = newp2;
|
||||||
depart0 = sp1;
|
depart0 = sp1;
|
||||||
arrivee0 = sp2;
|
arrivee0 = sp2;
|
||||||
ori_depart = ori_borne1;
|
ori_depart = o1;
|
||||||
ori_arrivee = ori_borne2;
|
ori_arrivee = o2;
|
||||||
} else {
|
} else {
|
||||||
depart = newp2;
|
depart = newp2;
|
||||||
arrivee = newp1;
|
arrivee = newp1;
|
||||||
depart0 = sp2;
|
depart0 = sp2;
|
||||||
arrivee0 = sp1;
|
arrivee0 = sp1;
|
||||||
ori_depart = ori_borne2;
|
ori_depart = o2;
|
||||||
ori_arrivee = ori_borne1;
|
ori_arrivee = o1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// debut du trajet
|
// debut du trajet
|
||||||
t.moveTo(depart0);
|
points << depart0;
|
||||||
|
|
||||||
// prolongement de la borne de depart
|
// prolongement de la borne de depart
|
||||||
t.lineTo(depart);
|
points << depart;
|
||||||
|
|
||||||
// commence le vrai trajet
|
// commence le vrai trajet
|
||||||
if (depart.y() < arrivee.y()) {
|
if (depart.y() < arrivee.y()) {
|
||||||
@@ -174,40 +193,71 @@ void Conducteur::priv_calculeConducteur(const QPointF &p1, const QPointF &p2) {
|
|||||||
if ((ori_depart == Borne::Nord && (ori_arrivee == Borne::Sud || ori_arrivee == Borne::Ouest)) || (ori_depart == Borne::Est && ori_arrivee == Borne::Ouest)) {
|
if ((ori_depart == Borne::Nord && (ori_arrivee == Borne::Sud || ori_arrivee == Borne::Ouest)) || (ori_depart == Borne::Est && ori_arrivee == Borne::Ouest)) {
|
||||||
// cas « 3 »
|
// cas « 3 »
|
||||||
qreal ligne_inter_x = (depart.x() + arrivee.x()) / 2.0;
|
qreal ligne_inter_x = (depart.x() + arrivee.x()) / 2.0;
|
||||||
t.lineTo(ligne_inter_x, depart.y());
|
points << QPointF(ligne_inter_x, depart.y());
|
||||||
t.lineTo(ligne_inter_x, arrivee.y());
|
points << QPointF(ligne_inter_x, arrivee.y());
|
||||||
} else if ((ori_depart == Borne::Sud && (ori_arrivee == Borne::Nord || ori_arrivee == Borne::Est)) || (ori_depart == Borne::Ouest && ori_arrivee == Borne::Est)) {
|
} else if ((ori_depart == Borne::Sud && (ori_arrivee == Borne::Nord || ori_arrivee == Borne::Est)) || (ori_depart == Borne::Ouest && ori_arrivee == Borne::Est)) {
|
||||||
// cas « 4 »
|
// cas « 4 »
|
||||||
qreal ligne_inter_y = (depart.y() + arrivee.y()) / 2.0;
|
qreal ligne_inter_y = (depart.y() + arrivee.y()) / 2.0;
|
||||||
t.lineTo(depart.x(), ligne_inter_y);
|
points << QPointF(depart.x(), ligne_inter_y);
|
||||||
t.lineTo(arrivee.x(), ligne_inter_y);
|
points << QPointF(arrivee.x(), ligne_inter_y);
|
||||||
} else if ((ori_depart == Borne::Nord || ori_depart == Borne::Est) && (ori_arrivee == Borne::Nord || ori_arrivee == Borne::Est)) {
|
} else if ((ori_depart == Borne::Nord || ori_depart == Borne::Est) && (ori_arrivee == Borne::Nord || ori_arrivee == Borne::Est)) {
|
||||||
t.lineTo(arrivee.x(), depart.y()); // cas « 2 »
|
points << QPointF(arrivee.x(), depart.y()); // cas « 2 »
|
||||||
} else t.lineTo(depart.x(), arrivee.y()); // cas « 1 »
|
} else {
|
||||||
|
points << QPointF(depart.x(), arrivee.y()); // cas « 1 »
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// trajet montant
|
// trajet montant
|
||||||
if ((ori_depart == Borne::Ouest && (ori_arrivee == Borne::Est || ori_arrivee == Borne::Sud)) || (ori_depart == Borne::Nord && ori_arrivee == Borne::Sud)) {
|
if ((ori_depart == Borne::Ouest && (ori_arrivee == Borne::Est || ori_arrivee == Borne::Sud)) || (ori_depart == Borne::Nord && ori_arrivee == Borne::Sud)) {
|
||||||
// cas « 3 »
|
// cas « 3 »
|
||||||
qreal ligne_inter_y = (depart.y() + arrivee.y()) / 2.0;
|
qreal ligne_inter_y = (depart.y() + arrivee.y()) / 2.0;
|
||||||
t.lineTo(depart.x(), ligne_inter_y);
|
points << QPointF(depart.x(), ligne_inter_y);
|
||||||
t.lineTo(arrivee.x(), ligne_inter_y);
|
points << QPointF(arrivee.x(), ligne_inter_y);
|
||||||
} else if ((ori_depart == Borne::Est && (ori_arrivee == Borne::Ouest || ori_arrivee == Borne::Nord)) || (ori_depart == Borne::Sud && ori_arrivee == Borne::Nord)) {
|
} else if ((ori_depart == Borne::Est && (ori_arrivee == Borne::Ouest || ori_arrivee == Borne::Nord)) || (ori_depart == Borne::Sud && ori_arrivee == Borne::Nord)) {
|
||||||
// cas « 4 »
|
// cas « 4 »
|
||||||
qreal ligne_inter_x = (depart.x() + arrivee.x()) / 2.0;
|
qreal ligne_inter_x = (depart.x() + arrivee.x()) / 2.0;
|
||||||
t.lineTo(ligne_inter_x, depart.y());
|
points << QPointF(ligne_inter_x, depart.y());
|
||||||
t.lineTo(ligne_inter_x, arrivee.y());
|
points << QPointF(ligne_inter_x, arrivee.y());
|
||||||
} else if ((ori_depart == Borne::Ouest || ori_depart == Borne::Nord) && (ori_arrivee == Borne::Ouest || ori_arrivee == Borne::Nord)) {
|
} else if ((ori_depart == Borne::Ouest || ori_depart == Borne::Nord) && (ori_arrivee == Borne::Ouest || ori_arrivee == Borne::Nord)) {
|
||||||
t.lineTo(depart.x(), arrivee.y()); // cas « 2 »
|
points << QPointF(depart.x(), arrivee.y()); // cas « 2 »
|
||||||
} else t.lineTo(arrivee.x(), depart.y()); // cas « 1 »
|
} else {
|
||||||
|
points << QPointF(arrivee.x(), depart.y()); // cas « 1 »
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fin du vrai trajet
|
// fin du vrai trajet
|
||||||
t.lineTo(arrivee);
|
points << arrivee;
|
||||||
|
|
||||||
// prolongement de la borne d'arrivee
|
// prolongement de la borne d'arrivee
|
||||||
t.lineTo(arrivee0);
|
points << arrivee0;
|
||||||
|
|
||||||
setPath(t);
|
pointsToPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Prolonge une borne.
|
||||||
|
@param terminal Le point correspondant a la borne
|
||||||
|
@param terminal_orientation L'orientation de la borne
|
||||||
|
@param ext_size la taille de la prolongation
|
||||||
|
@return le point correspondant a la borne apres prolongation
|
||||||
|
*/
|
||||||
|
QPointF Conducteur::extendTerminal(const QPointF &terminal, Borne::Orientation terminal_orientation, qreal ext_size) {
|
||||||
|
QPointF extended_terminal;
|
||||||
|
switch(terminal_orientation) {
|
||||||
|
case Borne::Nord:
|
||||||
|
extended_terminal = QPointF(terminal.x(), terminal.y() - ext_size);
|
||||||
|
break;
|
||||||
|
case Borne::Est:
|
||||||
|
extended_terminal = QPointF(terminal.x() + ext_size, terminal.y());
|
||||||
|
break;
|
||||||
|
case Borne::Sud:
|
||||||
|
extended_terminal = QPointF(terminal.x(), terminal.y() + ext_size);
|
||||||
|
break;
|
||||||
|
case Borne::Ouest:
|
||||||
|
extended_terminal = QPointF(terminal.x() - ext_size, terminal.y());
|
||||||
|
break;
|
||||||
|
default: extended_terminal = terminal;
|
||||||
|
}
|
||||||
|
return(extended_terminal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -218,28 +268,29 @@ void Conducteur::priv_calculeConducteur(const QPointF &p1, const QPointF &p2) {
|
|||||||
*/
|
*/
|
||||||
void Conducteur::paint(QPainter *qp, const QStyleOptionGraphicsItem */*qsogi*/, QWidget */*qw*/) {
|
void Conducteur::paint(QPainter *qp, const QStyleOptionGraphicsItem */*qsogi*/, QWidget */*qw*/) {
|
||||||
qp -> save();
|
qp -> save();
|
||||||
qp -> setRenderHint(QPainter::Antialiasing, false);
|
qp -> setRenderHint(QPainter::Antialiasing, false);
|
||||||
qp -> setRenderHint(QPainter::TextAntialiasing, false);
|
|
||||||
qp -> setRenderHint(QPainter::SmoothPixmapTransform, false);
|
|
||||||
|
|
||||||
// recupere le QPen et la QBrush du QPainter
|
// affectation du QPen et de la QBrush modifies au QPainter
|
||||||
QPen pen = qp -> pen();
|
qp -> setBrush(conducer_brush);
|
||||||
QBrush brush = qp -> brush();
|
//qp -> setBrush(Qt::green);
|
||||||
|
qp -> setPen(conducer_pen);
|
||||||
// attributs par defaut
|
if (isSelected()) {
|
||||||
pen.setJoinStyle(Qt::MiterJoin);
|
QPen tmp = qp -> pen();
|
||||||
pen.setCapStyle(Qt::SquareCap);
|
tmp.setColor(Qt::red);
|
||||||
pen.setColor(isSelected() ? Qt::red : Qt::black);
|
qp -> setPen(tmp);
|
||||||
pen.setStyle(Qt::SolidLine);
|
}
|
||||||
pen.setWidthF(1.0);
|
|
||||||
brush.setStyle(Qt::NoBrush);
|
|
||||||
|
|
||||||
// affectation du QPen et de la QBrush modifies au QPainter
|
|
||||||
qp -> setPen(pen);
|
|
||||||
qp -> setBrush(brush);
|
|
||||||
|
|
||||||
|
// dessin du conducteur
|
||||||
qp -> drawPath(path());
|
qp -> drawPath(path());
|
||||||
//QGraphicsPathItem::paint(qp, qsogi, qw);
|
|
||||||
|
// dessin des points d'accroche du conducteur si celui-ci est selectionne
|
||||||
|
if (isSelected()) {
|
||||||
|
qp -> setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
for (int i = 1 ; i < (points.size() -1) ; ++ i) {
|
||||||
|
QPointF point = points.at(i);
|
||||||
|
qp -> drawEllipse(QRectF(point.x() - 3.0, point.y() - 3.0, 6.0, 6.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
qp -> restore();
|
qp -> restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,3 +356,238 @@ bool Conducteur::valideXml(QDomElement &e){
|
|||||||
if (!conv_ok) return(false);
|
if (!conv_ok) return(false);
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Gere les clics sur le conducteur.
|
||||||
|
@param e L'evenement decrivant le clic.
|
||||||
|
*/
|
||||||
|
void Conducteur::mousePressEvent(QGraphicsSceneMouseEvent *e) {
|
||||||
|
// clic gauche
|
||||||
|
if (e -> buttons() & Qt::LeftButton) {
|
||||||
|
press_point = mapFromScene(e -> pos());
|
||||||
|
moving_point = false;
|
||||||
|
for (int i = 1 ; i < points.count() ; ++ i) {
|
||||||
|
QPointF point = points.at(i);
|
||||||
|
if (
|
||||||
|
press_point.x() >= point.x() - 5.0 &&\
|
||||||
|
press_point.x() < point.x() + 5.0 &&\
|
||||||
|
press_point.y() >= point.y() - 5.0 &&\
|
||||||
|
press_point.y() < point.y() + 5.0
|
||||||
|
) {
|
||||||
|
moving_point = true;
|
||||||
|
moved_point = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QGraphicsPathItem::mousePressEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Gere les deplacements de souris sur le conducteur.
|
||||||
|
@param e L'evenement decrivant le deplacement de souris.
|
||||||
|
@todo
|
||||||
|
-calculer le trajet du conducteur differemment selon l'etat du flag "trajet modifie"
|
||||||
|
-garder une liste des points constituants le trajet
|
||||||
|
-lorsque le fil est selectionne, dessiner ces points (cercles)
|
||||||
|
-lors d'un mousemoveevent: detecter la position du clic : si cela tombe dans la zone d'un point :
|
||||||
|
-deplacer ce point en consequence
|
||||||
|
-mettre le flag "trajet modifie" a true
|
||||||
|
-gerer les contraintes
|
||||||
|
*/
|
||||||
|
void Conducteur::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
|
||||||
|
// clic gauche
|
||||||
|
if (e -> buttons() & Qt::LeftButton) {
|
||||||
|
if (moving_point) {
|
||||||
|
/* recuperation de quelques joyeusetes tres souvent consultees */
|
||||||
|
// indice du dernier point ( = point non modifiable)
|
||||||
|
int ind_max_point = points.count() - 1;
|
||||||
|
|
||||||
|
// position precedente du point
|
||||||
|
QPointF p = points.at(moved_point);
|
||||||
|
qreal p_x = p.x();
|
||||||
|
qreal p_y = p.y();
|
||||||
|
|
||||||
|
// position pointee par la souris
|
||||||
|
qreal mouse_x = e -> pos().x();
|
||||||
|
qreal mouse_y = e -> pos().y();
|
||||||
|
|
||||||
|
// position du point apres le deplacement
|
||||||
|
qreal new_pos_x;
|
||||||
|
qreal new_pos_y;
|
||||||
|
|
||||||
|
if (moved_point == 1 || moved_point == ind_max_point - 1) {
|
||||||
|
/* premier et dernier points modifiables du conducteur */
|
||||||
|
// repere le point qui va imposer la contrainte de base
|
||||||
|
int ind_depend = moved_point == 1 ? 0 : ind_max_point;
|
||||||
|
qreal depend_x = points.at(ind_depend).x();
|
||||||
|
qreal depend_y = points.at(ind_depend).y();
|
||||||
|
|
||||||
|
// repere le point voisin suivant
|
||||||
|
int ind_voisin = moved_point == 1 ? 2 : moved_point - 1;
|
||||||
|
qreal voisin_x = points.at(ind_voisin).x();
|
||||||
|
qreal voisin_y = points.at(ind_voisin).y();
|
||||||
|
|
||||||
|
if (p_x == depend_x && p_y != depend_y) {
|
||||||
|
// deplacements limites a l'axe vertical
|
||||||
|
new_pos_x = p_x;
|
||||||
|
// si on peut aller plus loin que le point voisin suivant, on le fait... en deplacant le point voisin
|
||||||
|
if (p_x > voisin_x - 1 && p_x < voisin_x + 1) new_pos_y = conducer_bound(mouse_y, depend_y, voisin_y);
|
||||||
|
else {
|
||||||
|
new_pos_y = conducer_bound(mouse_y, depend_y, depend_y < voisin_y);
|
||||||
|
points.replace(ind_voisin, QPointF(voisin_x, new_pos_y));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// deplacements limites a l'axe horizontal
|
||||||
|
// si on peut aller plus loin que le point voisin suivant, on le fait... en deplacant le point voisin
|
||||||
|
if (p_y > voisin_y - 1 && p_y < voisin_y + 1) new_pos_x = conducer_bound(mouse_x, depend_x, voisin_x);
|
||||||
|
else {
|
||||||
|
new_pos_x = conducer_bound(mouse_x, depend_x, depend_x < voisin_x);
|
||||||
|
points.replace(ind_voisin, QPointF(new_pos_x, voisin_y));
|
||||||
|
}
|
||||||
|
new_pos_y = p_y;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* autres points */
|
||||||
|
new_pos_x = mouse_x;
|
||||||
|
new_pos_y = mouse_y;
|
||||||
|
|
||||||
|
/* deplace les deux points voisins (sans cela, le deplacement du point n'est pas possible) */
|
||||||
|
// point precedent
|
||||||
|
int ind_point_precedent = moved_point - 1;
|
||||||
|
qreal pp_x = points.at(ind_point_precedent).x();
|
||||||
|
qreal pp_y = points.at(ind_point_precedent).y();
|
||||||
|
if (ind_point_precedent != 1) {
|
||||||
|
if (pp_x > p_x - 1 && pp_x < p_x + 1) {
|
||||||
|
points.replace(ind_point_precedent, QPointF(new_pos_x, pp_y));
|
||||||
|
} else {
|
||||||
|
points.replace(ind_point_precedent, QPointF(pp_x, new_pos_y));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pp_x > p_x - 1 && pp_x < p_x + 1) {
|
||||||
|
new_pos_x = p_x;
|
||||||
|
} else {
|
||||||
|
new_pos_y = p_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// point suivant
|
||||||
|
int ind_point_suivant = moved_point + 1;
|
||||||
|
qreal ps_x = points.at(ind_point_suivant).x();
|
||||||
|
qreal ps_y = points.at(ind_point_suivant).y();
|
||||||
|
if (ind_point_suivant != ind_max_point - 1) {
|
||||||
|
if (ps_x > p_x - 1 && ps_x < p_x + 1) {
|
||||||
|
points.replace(ind_point_suivant, QPointF(new_pos_x, ps_y));
|
||||||
|
} else {
|
||||||
|
points.replace(ind_point_suivant, QPointF(ps_x, new_pos_y));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ps_x > p_x - 1 && ps_x < p_x + 1) {
|
||||||
|
new_pos_x = p_x;
|
||||||
|
} else {
|
||||||
|
new_pos_y = p_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// application du deplacement
|
||||||
|
modified_path = true;
|
||||||
|
points.replace(moved_point, QPointF(new_pos_x, new_pos_y));
|
||||||
|
updatePoints();
|
||||||
|
pointsToPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QGraphicsPathItem::mouseMoveEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Gere les relachements de boutons de souris sur le conducteur
|
||||||
|
@param e L'evenement decrivant le lacher de bouton.
|
||||||
|
*/
|
||||||
|
void Conducteur::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
|
||||||
|
// clic gauche
|
||||||
|
if (e -> buttons() & Qt::LeftButton) {
|
||||||
|
moving_point = false;
|
||||||
|
QGraphicsPathItem::mouseReleaseEvent(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return Le rectangle delimitant l'espace de dessin du conducteur
|
||||||
|
*/
|
||||||
|
QRectF Conducteur::boundingRect() const {
|
||||||
|
QRectF retour = QGraphicsPathItem::boundingRect();
|
||||||
|
retour.adjust(-5.0, -5.0, 5.0, 5.0);
|
||||||
|
return(retour);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return La forme / zone "cliquable" du conducteur
|
||||||
|
*/
|
||||||
|
QPainterPath Conducteur::shape() const {
|
||||||
|
QPainterPath area;
|
||||||
|
QPointF previous_point;
|
||||||
|
QPointF *point1, *point2;
|
||||||
|
foreach(QPointF point, points) {
|
||||||
|
if (!previous_point.isNull()) {
|
||||||
|
if (point.x() == previous_point.x()) {
|
||||||
|
if (point.y() <= previous_point.y()) {
|
||||||
|
point1 = &point;
|
||||||
|
point2 = &previous_point;
|
||||||
|
} else {
|
||||||
|
point1 = &previous_point;
|
||||||
|
point2 = &point;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (point.x() <= previous_point.x()) {
|
||||||
|
point1 = &point;
|
||||||
|
point2 = &previous_point;
|
||||||
|
} else {
|
||||||
|
point1 = &previous_point;
|
||||||
|
point2 = &point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qreal p1_x = point1 -> x();
|
||||||
|
qreal p1_y = point1 -> y();
|
||||||
|
qreal p2_x = point2 -> x();
|
||||||
|
qreal p2_y = point2 -> y();
|
||||||
|
area.setFillRule(Qt::OddEvenFill);
|
||||||
|
area.addRect(p1_x - 5.0, p1_y - 5.0, 10.0 + p2_x - p1_x, 10.0 + p2_y - p1_y);
|
||||||
|
}
|
||||||
|
previous_point = point;
|
||||||
|
area.setFillRule(Qt::WindingFill);
|
||||||
|
area.addRect(point.x() - 5.0, point.y() - 5.0, 10.0, 10.0);
|
||||||
|
}
|
||||||
|
return(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Met à jour deux listes de reels.
|
||||||
|
*/
|
||||||
|
void Conducteur::updatePoints() {
|
||||||
|
int s = points.size();
|
||||||
|
moves_x.clear();
|
||||||
|
moves_y.clear();
|
||||||
|
for (int i = 1 ; i < s ; ++ i) {
|
||||||
|
moves_x << points.at(i).x() - points.at(i - 1).x();
|
||||||
|
moves_y << points.at(i).y() - points.at(i - 1).y();
|
||||||
|
}
|
||||||
|
QPointF b1 = points.at(0);
|
||||||
|
QPointF b2 = points.at(s - 1);
|
||||||
|
orig_dist_2_terms_x = b2.x() - b1.x();
|
||||||
|
orig_dist_2_terms_y = b2.y() - b1.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal Conducteur::conducer_bound(qreal tobound, qreal bound1, qreal bound2) {
|
||||||
|
qreal space = 5.0;
|
||||||
|
if (bound1 < bound2) {
|
||||||
|
return(qBound(bound1 + space, tobound, bound2 - space));
|
||||||
|
} else {
|
||||||
|
return(qBound(bound2 + space, tobound, bound1 - space));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal Conducteur::conducer_bound(qreal tobound, qreal bound, bool positive) {
|
||||||
|
qreal space = 5.0;
|
||||||
|
return(positive ? qMax(tobound, bound + space) : qMin(tobound, bound - space));
|
||||||
|
}
|
||||||
|
|||||||
40
conducteur.h
40
conducteur.h
@@ -16,24 +16,48 @@
|
|||||||
void destroy();
|
void destroy();
|
||||||
bool isDestroyed() const { return(destroyed); }
|
bool isDestroyed() const { return(destroyed); }
|
||||||
void updateWithNewPos(const QRectF &, const Borne *, const QPointF &);
|
void updateWithNewPos(const QRectF &, const Borne *, const QPointF &);
|
||||||
void update(const QRectF &);
|
void update(const QRectF & = QRectF());
|
||||||
void update(qreal, qreal, qreal, qreal);
|
|
||||||
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
|
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
|
||||||
|
QRectF boundingRect() const;
|
||||||
|
virtual QPainterPath shape() const;
|
||||||
static bool valideXml(QDomElement &);
|
static bool valideXml(QDomElement &);
|
||||||
|
|
||||||
///Premiere borne a laquelle le fil est rattache
|
///Premiere borne a laquelle le fil est rattache
|
||||||
Borne *borne1;
|
Borne *borne1;
|
||||||
///Deuxieme borne a laquelle le fil est rattache
|
///Deuxieme borne a laquelle le fil est rattache
|
||||||
Borne *borne2;
|
Borne *borne2;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mousePressEvent(QGraphicsSceneMouseEvent *);
|
||||||
|
void mouseMoveEvent(QGraphicsSceneMouseEvent *);
|
||||||
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// booleen indiquant si le fil est encore valide
|
/// booleen indiquant si le fil est encore valide
|
||||||
bool destroyed;
|
bool destroyed;
|
||||||
|
QList<QPointF> points;
|
||||||
|
QList<qreal> moves_x;
|
||||||
|
QList<qreal> moves_y;
|
||||||
|
qreal orig_dist_2_terms_x;
|
||||||
|
qreal orig_dist_2_terms_y;
|
||||||
|
bool type_trajet_x;
|
||||||
|
QPointF press_point;
|
||||||
|
bool moving_point;
|
||||||
|
int moved_point;
|
||||||
|
bool modified_path;
|
||||||
|
static QPen conducer_pen;
|
||||||
|
static QBrush conducer_brush;
|
||||||
|
static bool pen_and_brush_initialized;
|
||||||
|
|
||||||
void calculeConducteur();
|
void pointsToPath();
|
||||||
void calculeConducteurWithNewPos(const Borne *, const QPointF &);
|
void updatePoints();
|
||||||
void priv_calculeConducteur(const QPointF &, const QPointF &);
|
void priv_calculeConducteur(const QPointF &, Borne::Orientation, const QPointF &, Borne::Orientation);
|
||||||
bool surLeMemeAxe(Borne::Orientation, Borne::Orientation);
|
void priv_modifieConducteur(const QPointF &, Borne::Orientation, const QPointF &, Borne::Orientation);
|
||||||
bool estHorizontale(Borne::Orientation a);
|
static QPointF extendTerminal(const QPointF &, Borne::Orientation, qreal = 12.0);
|
||||||
bool estVerticale(Borne::Orientation a);
|
static bool surLeMemeAxe(Borne::Orientation, Borne::Orientation);
|
||||||
|
static bool estHorizontale(Borne::Orientation a);
|
||||||
|
static bool estVerticale(Borne::Orientation a);
|
||||||
|
static qreal conducer_bound(qreal tobound, qreal bound1, qreal bound2);
|
||||||
|
static qreal conducer_bound(qreal tobound, qreal bound, bool positive);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ void SchemaVue::setAntialiasing(bool aa) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
appelle la methode select sur tous les elements de la liste d'elements
|
appelle la methode select sur tous les elements de la liste d'elements
|
||||||
@todo modifier selectAll pour l'integration des conducteurs
|
|
||||||
*/
|
*/
|
||||||
void SchemaVue::selectAll() {
|
void SchemaVue::selectAll() {
|
||||||
if (scene -> items().isEmpty()) return;
|
if (scene -> items().isEmpty()) return;
|
||||||
@@ -61,7 +60,6 @@ void SchemaVue::selectAll() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
appelle la methode deselect sur tous les elements de la liste d'elements
|
appelle la methode deselect sur tous les elements de la liste d'elements
|
||||||
@todo modifier selectNothing pour l'integration des conducteurs
|
|
||||||
*/
|
*/
|
||||||
void SchemaVue::selectNothing() {
|
void SchemaVue::selectNothing() {
|
||||||
if (scene -> items().isEmpty()) return;
|
if (scene -> items().isEmpty()) return;
|
||||||
@@ -70,7 +68,6 @@ void SchemaVue::selectNothing() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
Inverse l'etat de selection de tous les elements de la liste d'elements
|
Inverse l'etat de selection de tous les elements de la liste d'elements
|
||||||
@todo modifier selectInvert pour l'integration des conducteurs
|
|
||||||
*/
|
*/
|
||||||
void SchemaVue::selectInvert() {
|
void SchemaVue::selectInvert() {
|
||||||
if (scene -> items().isEmpty()) return;
|
if (scene -> items().isEmpty()) return;
|
||||||
@@ -389,7 +386,6 @@ bool SchemaVue::enregistrer() {
|
|||||||
Si l'enregistrement reussit, le nom du fichier est conserve et la fonction renvoie true.
|
Si l'enregistrement reussit, le nom du fichier est conserve et la fonction renvoie true.
|
||||||
Sinon, faux est renvoye.
|
Sinon, faux est renvoye.
|
||||||
@return true si l'enregistrement a reussi, false sinon
|
@return true si l'enregistrement a reussi, false sinon
|
||||||
@todo detecter le chemin du bureau automatiquement
|
|
||||||
*/
|
*/
|
||||||
bool SchemaVue::enregistrer_sous() {
|
bool SchemaVue::enregistrer_sous() {
|
||||||
// demande un nom de fichier a l'utilisateur pour enregistrer le schema
|
// demande un nom de fichier a l'utilisateur pour enregistrer le schema
|
||||||
|
|||||||
Reference in New Issue
Block a user