Desactivation temporaire de l'edition des conducteurs par les points de jonction ; Implementation de l'edition des conducteurs par des points de saisie situes en leur milieu

git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@54 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
xavierqet
2007-02-14 01:08:29 +00:00
parent 1e486712cc
commit 8c491de218
6 changed files with 708 additions and 124 deletions

View File

@@ -1,5 +1,6 @@
#include <QtDebug> #include <QtDebug>
#include "conducer.h" #include "conducer.h"
#include "conducersegment.h"
#include "element.h" #include "element.h"
bool Conducer::pen_and_brush_initialized = false; bool Conducer::pen_and_brush_initialized = false;
@@ -36,6 +37,7 @@ Conducer::Conducer(Terminal *p1, Terminal* p2, Element *parent, QGraphicsScene *
pen_and_brush_initialized = true; pen_and_brush_initialized = true;
} }
// calcul du rendu du conducteur // calcul du rendu du conducteur
segments = NULL;
priv_calculeConducer(terminal1 -> amarrageConducer(), terminal1 -> orientation(), terminal2 -> amarrageConducer(), terminal2 -> orientation()); priv_calculeConducer(terminal1 -> amarrageConducer(), terminal1 -> orientation(), terminal2 -> amarrageConducer(), terminal2 -> orientation());
setFlags(QGraphicsItem::ItemIsSelectable); setFlags(QGraphicsItem::ItemIsSelectable);
} }
@@ -47,7 +49,7 @@ Conducer::Conducer(Terminal *p1, Terminal* p2, Element *parent, QGraphicsScene *
void Conducer::update(const QRectF &rect) { void Conducer::update(const QRectF &rect) {
// utilise soit la fonction priv_modifieConducteur soit la fonction priv_calculeConducteur // utilise soit la fonction priv_modifieConducteur soit la fonction priv_calculeConducteur
void (Conducer::* fonction_update) (const QPointF &, Terminal::Orientation, const QPointF &, Terminal::Orientation); void (Conducer::* fonction_update) (const QPointF &, Terminal::Orientation, const QPointF &, Terminal::Orientation);
fonction_update = (points.count() && modified_path) ? &Conducer::priv_modifieConducer : &Conducer::priv_calculeConducer; fonction_update = (nbSegments() && modified_path) ? &Conducer::priv_modifieConducer : &Conducer::priv_calculeConducer;
// appelle la bonne fonction pour calculer l'aspect du conducteur // appelle la bonne fonction pour calculer l'aspect du conducteur
(this ->* fonction_update)( (this ->* fonction_update)(
@@ -76,7 +78,7 @@ void Conducer::updateWithNewPos(const QRectF &rect, const Terminal *b, const QPo
p1 = terminal1 -> amarrageConducer(); p1 = terminal1 -> amarrageConducer();
p2 = terminal2 -> amarrageConducer(); p2 = terminal2 -> amarrageConducer();
} }
if (points.count() && modified_path) if (nbSegments() && modified_path)
priv_modifieConducer(p1, terminal1 -> orientation(), p2, terminal2 -> orientation()); priv_modifieConducer(p1, terminal1 -> orientation(), p2, terminal2 -> orientation());
else else
priv_calculeConducer(p1, terminal1 -> orientation(), p2, terminal2 -> orientation()); priv_calculeConducer(p1, terminal1 -> orientation(), p2, terminal2 -> orientation());
@@ -86,15 +88,27 @@ void Conducer::updateWithNewPos(const QRectF &rect, const Terminal *b, const QPo
/** /**
Genere le QPainterPath a partir de la liste des points Genere le QPainterPath a partir de la liste des points
*/ */
void Conducer::pointsToPath() { void Conducer::segmentsToPath() {
// chemin qui sera dessine
QPainterPath path; QPainterPath path;
bool moveto_done = false;
foreach(QPointF point, points) { // s'il n'y a pa des segments, on arrete la
if (!moveto_done) { if (segments == NULL) setPath(path);
path.moveTo(point);
moveto_done = true; // demarre le chemin
} else path.lineTo(point); path.moveTo(segments -> firstPoint());
// parcourt les segments pour dessiner le chemin
ConducerSegment *segment = segments;
while(segment -> hasNextSegment()) {
path.lineTo(segment -> secondPoint());
segment = segment -> nextSegment();
} }
// termine le chemin
path.lineTo(segment -> secondPoint());
// affecte le chemin au conducteur
setPath(path); setPath(path);
} }
@@ -106,7 +120,7 @@ void Conducer::pointsToPath() {
@param o2 Orientation de la borne 2 @param o2 Orientation de la borne 2
*/ */
void Conducer::priv_modifieConducer(const QPointF &p1, Terminal::Orientation, const QPointF &p2, Terminal::Orientation) { void Conducer::priv_modifieConducer(const QPointF &p1, Terminal::Orientation, const QPointF &p2, Terminal::Orientation) {
Q_ASSERT_X(points.count() > 1, "priv_modifieConducer", "pas de points a modifier"); Q_ASSERT_X(nbSegments() > 1, "priv_modifieConducer", "pas de points a modifier");
// recupere les dernieres coordonnees connues des bornes // recupere les dernieres coordonnees connues des bornes
QPointF old_p1 = mapFromScene(terminal1 -> amarrageConducer()); QPointF old_p1 = mapFromScene(terminal1 -> amarrageConducer());
@@ -130,7 +144,8 @@ void Conducer::priv_modifieConducer(const QPointF &p1, Terminal::Orientation, co
// genere les nouveaux points // genere les nouveaux points
int limite = moves_x.size() - 1; int limite = moves_x.size() - 1;
int coeff = type_trajet_x ? 1 : -1; int coeff = type_trajet_x ? 1 : -1;
points.clear();
QList<QPointF> points;
points << (type_trajet_x ? new_p1 : new_p2); points << (type_trajet_x ? new_p1 : new_p2);
for (int i = 0 ; i < limite ; ++ i) { for (int i = 0 ; i < limite ; ++ i) {
QPointF previous_point = points.last(); QPointF previous_point = points.last();
@@ -140,8 +155,8 @@ void Conducer::priv_modifieConducer(const QPointF &p1, Terminal::Orientation, co
); );
} }
points << (type_trajet_x ? new_p2 : new_p1); points << (type_trajet_x ? new_p2 : new_p1);
pointsToSegments(points);
pointsToPath(); segmentsToPath();
} }
/** /**
@@ -154,7 +169,10 @@ void Conducer::priv_modifieConducer(const QPointF &p1, Terminal::Orientation, co
void Conducer::priv_calculeConducer(const QPointF &p1, Terminal::Orientation o1, const QPointF &p2, Terminal::Orientation o2) { void Conducer::priv_calculeConducer(const QPointF &p1, Terminal::Orientation o1, const QPointF &p2, Terminal::Orientation o2) {
QPointF sp1, sp2, depart, newp1, newp2, arrivee, depart0, arrivee0; QPointF sp1, sp2, depart, newp1, newp2, arrivee, depart0, arrivee0;
Terminal::Orientation ori_depart, ori_arrivee; Terminal::Orientation ori_depart, ori_arrivee;
points.clear();
// s'assure qu'il n'y a ni points
QList<QPointF> points;
type_trajet_x = p1.x() < p2.x(); type_trajet_x = p1.x() < p2.x();
// mappe les points par rapport a la scene // mappe les points par rapport a la scene
sp1 = mapFromScene(p1); sp1 = mapFromScene(p1);
@@ -230,7 +248,8 @@ void Conducer::priv_calculeConducer(const QPointF &p1, Terminal::Orientation o1,
// prolongement de la borne d'arrivee // prolongement de la borne d'arrivee
points << arrivee0; points << arrivee0;
pointsToPath(); pointsToSegments(points);
segmentsToPath();
} }
/** /**
@@ -272,7 +291,6 @@ void Conducer::paint(QPainter *qp, const QStyleOptionGraphicsItem */*qsogi*/, QW
// affectation du QPen et de la QBrush modifies au QPainter // affectation du QPen et de la QBrush modifies au QPainter
qp -> setBrush(conducer_brush); qp -> setBrush(conducer_brush);
//qp -> setBrush(Qt::green);
qp -> setPen(conducer_pen); qp -> setPen(conducer_pen);
if (isSelected()) { if (isSelected()) {
QPen tmp = qp -> pen(); QPen tmp = qp -> pen();
@@ -286,9 +304,25 @@ void Conducer::paint(QPainter *qp, const QStyleOptionGraphicsItem */*qsogi*/, QW
// dessin des points d'accroche du conducteur si celui-ci est selectionne // dessin des points d'accroche du conducteur si celui-ci est selectionne
if (isSelected()) { if (isSelected()) {
qp -> setRenderHint(QPainter::Antialiasing, true); qp -> setRenderHint(QPainter::Antialiasing, true);
QList<QPointF> points = segmentsToPoints();
QPointF previous_point;
QBrush square_brush(Qt::darkGreen);
for (int i = 1 ; i < (points.size() -1) ; ++ i) { for (int i = 1 ; i < (points.size() -1) ; ++ i) {
QPointF point = points.at(i); QPointF point = points.at(i);
if (i > 1) {
qp -> fillRect(
QRectF(
((previous_point.x() + point.x()) / 2.0 ) - 2.5,
((previous_point.y() + point.y()) / 2.0 ) - 2.5,
5.0,
5.0
),
square_brush
);
}
qp -> drawEllipse(QRectF(point.x() - 3.0, point.y() - 3.0, 6.0, 6.0)); qp -> drawEllipse(QRectF(point.x() - 3.0, point.y() - 3.0, 6.0, 6.0));
previous_point = point;
} }
} }
qp -> restore(); qp -> restore();
@@ -364,20 +398,29 @@ bool Conducer::valideXml(QDomElement &e){
void Conducer::mousePressEvent(QGraphicsSceneMouseEvent *e) { void Conducer::mousePressEvent(QGraphicsSceneMouseEvent *e) {
// clic gauche // clic gauche
if (e -> buttons() & Qt::LeftButton) { if (e -> buttons() & Qt::LeftButton) {
// recupere les coordonnees du clic
press_point = mapFromScene(e -> pos()); press_point = mapFromScene(e -> pos());
moving_point = false;
for (int i = 1 ; i < points.count() ; ++ i) { /*
QPointF point = points.at(i); parcourt les segments pour determiner si le clic a eu lieu
if ( - sur l'extremite d'un segment
press_point.x() >= point.x() - 5.0 &&\ - sur le milieu d'un segment
press_point.x() < point.x() + 5.0 &&\ - ailleurs
press_point.y() >= point.y() - 5.0 &&\ */
press_point.y() < point.y() + 5.0 ConducerSegment *segment = segments;
) { while (segment -> hasNextSegment()) {
if (hasClickedOn(press_point, segment -> secondPoint())) {
moving_point = true; moving_point = true;
moved_point = i; moving_segment = false;
moved_segment = segment;
break;
} else if (hasClickedOn(press_point, segment -> middle())) {
moving_point = false;
moving_segment = true;
moved_segment = segment;
break; break;
} }
segment = segment -> nextSegment();
} }
} }
QGraphicsPathItem::mousePressEvent(e); QGraphicsPathItem::mousePressEvent(e);
@@ -398,103 +441,39 @@ void Conducer::mousePressEvent(QGraphicsSceneMouseEvent *e) {
void Conducer::mouseMoveEvent(QGraphicsSceneMouseEvent *e) { void Conducer::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
// clic gauche // clic gauche
if (e -> buttons() & Qt::LeftButton) { 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 // position pointee par la souris
qreal mouse_x = e -> pos().x(); qreal mouse_x = e -> pos().x();
qreal mouse_y = e -> pos().y(); qreal mouse_y = e -> pos().y();
// position du point apres le deplacement if (moving_point) {
qreal new_pos_x; // la modification par points revient bientot
qreal new_pos_y; /*
// position precedente du point
QPointF p = moved_segment -> secondPoint();
qreal p_x = p.x();
qreal p_y = p.y();
if (moved_point == 1 || moved_point == ind_max_point - 1) { // calcul du deplacement
/* premier et dernier points modifiables du conducteur */ moved_segment -> moveX(mouse_x - p_x());
// repere le point qui va imposer la contrainte de base moved_segment -> moveY(mouse_y - p_y());
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 // application du deplacement
modified_path = true; modified_path = true;
points.replace(moved_point, QPointF(new_pos_x, new_pos_y));
updatePoints(); updatePoints();
pointsToPath(); segmentsToPath();
*/
} else if (moving_segment) {
// position precedente du point
QPointF p = moved_segment -> middle();
// calcul du deplacement
moved_segment -> moveX(mouse_x - p.x());
moved_segment -> moveY(mouse_y - p.y());
// application du deplacement
modified_path = true;
updatePoints();
segmentsToPath();
} }
} }
QGraphicsPathItem::mouseMoveEvent(e); QGraphicsPathItem::mouseMoveEvent(e);
@@ -506,11 +485,10 @@ void Conducer::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
*/ */
void Conducer::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) { void Conducer::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
// clic gauche // clic gauche
if (e -> buttons() & Qt::LeftButton) {
moving_point = false; moving_point = false;
moving_segment = false;
QGraphicsPathItem::mouseReleaseEvent(e); QGraphicsPathItem::mouseReleaseEvent(e);
} }
}
/** /**
@return Le rectangle delimitant l'espace de dessin du conducteur @return Le rectangle delimitant l'espace de dessin du conducteur
@@ -525,6 +503,7 @@ QRectF Conducer::boundingRect() const {
@return La forme / zone "cliquable" du conducteur @return La forme / zone "cliquable" du conducteur
*/ */
QPainterPath Conducer::shape() const { QPainterPath Conducer::shape() const {
QList<QPointF> points = segmentsToPoints();
QPainterPath area; QPainterPath area;
QPointF previous_point; QPointF previous_point;
QPointF *point1, *point2; QPointF *point1, *point2;
@@ -565,6 +544,7 @@ QPainterPath Conducer::shape() const {
Met à jour deux listes de reels. Met à jour deux listes de reels.
*/ */
void Conducer::updatePoints() { void Conducer::updatePoints() {
QList<QPointF> points = segmentsToPoints();
int s = points.size(); int s = points.size();
moves_x.clear(); moves_x.clear();
moves_y.clear(); moves_y.clear();
@@ -591,3 +571,74 @@ qreal Conducer::conducer_bound(qreal tobound, qreal bound, bool positive) {
qreal space = 5.0; qreal space = 5.0;
return(positive ? qMax(tobound, bound + space) : qMin(tobound, bound - space)); return(positive ? qMax(tobound, bound + space) : qMin(tobound, bound - space));
} }
int Conducer::nbSegments() {
if (segments == NULL) return(0);
int nb_seg = 1;
ConducerSegment *segment = segments;
while (segment -> hasNextSegment()) {
++ nb_seg;
segment = segment -> nextSegment();
}
return(nb_seg);
}
/**
Genere une liste de points a partir des segments de ce conducteur
@return La liste de points representant ce conducteur
*/
QList<QPointF> Conducer::segmentsToPoints() const {
// liste qui sera retournee
QList<QPointF> points_list;
// on retourne la liste tout de suite s'il n'y a pas de segments
if (segments == NULL) return(points_list);
// recupere le premier point
points_list << segments -> firstPoint();
// parcourt les segments pour recuperer les autres points
ConducerSegment *segment = segments;
while(segment -> hasNextSegment()) {
points_list << segment -> secondPoint();
segment = segment -> nextSegment();
}
// recupere le dernier point
points_list << segment -> secondPoint();
//retourne la liste
return(points_list);
}
/**
Regenere les segments de ce conducteur a partir de la liste de points passee en parametre
@param points_list Liste de points a utiliser pour generer les segments
*/
void Conducer::pointsToSegments(QList<QPointF> points_list) {
// supprime les segments actuels
if (segments != NULL) {
ConducerSegment *segment = segments;
while (segment -> hasNextSegment()) {
ConducerSegment *nextsegment = segment -> nextSegment();
delete segment;
segment = nextsegment;
}
}
// cree les segments a partir de la liste de points
ConducerSegment *last_segment = NULL;
for (int i = 0 ; i < points_list.size() - 1 ; ++ i) {
last_segment = new ConducerSegment(points_list.at(i), points_list.at(i + 1), last_segment);
if (!i) segments = last_segment;
}
}
bool Conducer::hasClickedOn(QPointF press_point, QPointF point) {
return (
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
);
}

View File

@@ -2,6 +2,7 @@
#define CONDUCTEUR_H #define CONDUCTEUR_H
#include <QtGui> #include <QtGui>
#include "terminal.h" #include "terminal.h"
class ConducerSegment;
class Element; class Element;
/** /**
Cette classe represente un conducteur. Un conducteur relie deux bornes d'element. Cette classe represente un conducteur. Un conducteur relie deux bornes d'element.
@@ -35,7 +36,7 @@
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; ConducerSegment *segments;
QList<qreal> moves_x; QList<qreal> moves_x;
QList<qreal> moves_y; QList<qreal> moves_y;
qreal orig_dist_2_terms_x; qreal orig_dist_2_terms_x;
@@ -43,16 +44,23 @@
bool type_trajet_x; bool type_trajet_x;
QPointF press_point; QPointF press_point;
bool moving_point; bool moving_point;
bool moving_segment;
int moved_point; int moved_point;
ConducerSegment *moved_segment;
bool modified_path; bool modified_path;
static QPen conducer_pen; static QPen conducer_pen;
static QBrush conducer_brush; static QBrush conducer_brush;
static bool pen_and_brush_initialized; static bool pen_and_brush_initialized;
void pointsToPath(); void segmentsToPath();
void updatePoints(); void updatePoints();
void priv_calculeConducer(const QPointF &, Terminal::Orientation, const QPointF &, Terminal::Orientation); void priv_calculeConducer(const QPointF &, Terminal::Orientation, const QPointF &, Terminal::Orientation);
void priv_modifieConducer(const QPointF &, Terminal::Orientation, const QPointF &, Terminal::Orientation); void priv_modifieConducer(const QPointF &, Terminal::Orientation, const QPointF &, Terminal::Orientation);
int nbSegments();
QList<QPointF> segmentsToPoints() const;
void pointsToSegments(QList<QPointF>);
bool hasClickedOn(QPointF, QPointF);
static QPointF extendTerminal(const QPointF &, Terminal::Orientation, qreal = 12.0); static QPointF extendTerminal(const QPointF &, Terminal::Orientation, qreal = 12.0);
static bool surLeMemeAxe(Terminal::Orientation, Terminal::Orientation); static bool surLeMemeAxe(Terminal::Orientation, Terminal::Orientation);
static bool estHorizontale(Terminal::Orientation a); static bool estHorizontale(Terminal::Orientation a);

478
conducersegment.cpp Normal file
View File

@@ -0,0 +1,478 @@
#include "conducersegment.h"
#include <QDebug>
ConducerSegment::ConducerSegment(QPointF p1, QPointF p2, ConducerSegment *cs1, ConducerSegment *cs2) {
setFirstPoint(p1);
setSecondPoint(p2);
setPreviousSegment(cs1);
setNextSegment(cs2);
}
ConducerSegment::~ConducerSegment() {
if (hasPreviousSegment()) previousSegment() -> setNextSegment(nextSegment());
if (hasNextSegment()) nextSegment() -> setPreviousSegment(previousSegment());
}
/**
Permet de savoir s'il est possible de deplacer le premier point du segment
sans creer d'incoherence. La valeur du mouvement maximum qu'il est possible de faire
sans incoherence est stockee dans le second parametre.
@param asked_dx La valeur du mouvement demande
@param possible_dx La valeur du mouvement possible (au maximum)
@return true si le mouvement est possible ; false s'il doit etre limite
*/
bool ConducerSegment::canMove1stPointX(qreal asked_dx, qreal &possible_dx) {
Q_ASSERT_X(isVertical(), "ConducerSegment::canMove1stPointX", "segment non vertical");
/// On ne bouge jamais le premier point d'un segment statique.
if (!hasPreviousSegment()) {
possible_dx = 0.0;
return(false);
}
// a ce stade, on a forcement un segment precedent
/// Si le segment precedent n'est pas statique, le mouvement est possible.
if (previous_segment -> hasPreviousSegment()) {
possible_dx = asked_dx;
return(true);
}
// a ce stade, le segment precedent est forcement statique
/// Si le segment precedent est vertical, le mouvement est possible :
/// il induira la creation d'un segment horizontal supplementaire.
if (previous_segment -> isVertical()) {
possible_dx = asked_dx;
return(true);
}
// a ce stade, le segment precedent est forcement horizontal
// recupere quelques donnees
qreal prev_segment_first_x = previous_segment -> point1.x();
qreal first_x = point1.x();
/// Il se peut que le mouvement doive etre limite de facon a ce
/// que le segment statique conserve une taille minimale.
if (previous_segment -> length() > 0.0) {
if (first_x + asked_dx < prev_segment_first_x + 12.0) {
possible_dx = -(first_x - prev_segment_first_x - 12.0);
return(false);
} else {
possible_dx = asked_dx;
return(true);
}
} else {
if (first_x + asked_dx >= prev_segment_first_x - 12.0) {
possible_dx = prev_segment_first_x - 12.0 - first_x;
return(false);
} else {
possible_dx = asked_dx;
return(true);
}
}
}
/**
Permet de savoir s'il est possible de deplacer le second point du segment
sans creer d'incoherence. La valeur du mouvement maximum qu'il est possible de faire
sans incoherence est stockee dans le second parametre.
@param asked_dx La valeur du mouvement demande
@param possible_dx La valeur du mouvement possible (au maximum)
@return true si le mouvement est possible ; false s'il doit etre limite
*/
bool ConducerSegment::canMove2ndPointX(qreal asked_dx, qreal &possible_dx) {
Q_ASSERT_X(isVertical(), "ConducerSegment::canMove2ndPointX", "segment non vertical");
/// On ne modifie jamais l'ordonnee du second point d'un segment statique.
if (!hasNextSegment()) {
possible_dx = 0.0;
return(false);
}
// a ce stade, on a forcement un segment suivant
/// Si le segment suivant n'est pas statique, le mouvement est possible.
if (next_segment -> hasNextSegment()) {
possible_dx = asked_dx;
return(true);
}
// a ce stade, le segment suivant est forcement statique
/// Si le segment suivant est vertical, le mouvement est possible :
/// il induira la creation d'un segment horizontal supplementaire.
if (next_segment -> isVertical()) {
possible_dx = asked_dx;
return(true);
}
// a ce stade, le segment suivant est forcement horizontal
// recupere quelques donnees
qreal next_segment_second_x = next_segment -> point2.x();
qreal second_x = point2.x();
/// Il se peut que le mouvement doive etre limite de facon a ce
/// que le segment statique conserve une taille minimale.
if (next_segment -> length() < 0.0) {
if (second_x + asked_dx < next_segment_second_x + 12.0) {
possible_dx = second_x - next_segment_second_x - 12.0;
return(false);
} else {
possible_dx = asked_dx;
return(true);
}
} else {
if (second_x + asked_dx >= next_segment_second_x - 12.0) {
possible_dx = next_segment_second_x - 12.0 - second_x;
return(false);
} else {
possible_dx = asked_dx;
return(true);
}
}
}
/**
Permet de savoir s'il est possible de deplacer le premier point du segment
sans creer d'incoherence. La valeur du mouvement maximum qu'il est possible de faire
sans incoherence est stockee dans le second parametre.
@param asked_dy La valeur du mouvement demande
@param possible_dy La valeur du mouvement possible (au maximum)
@return true si le mouvement est possible ; false s'il doit etre limite
*/
bool ConducerSegment::canMove1stPointY(qreal asked_dy, qreal &possible_dy) {
Q_ASSERT_X(isHorizontal(), "ConducerSegment::canMove1stPointY", "segment non horizontal");
/// On ne bouge jamais le premier point d'un segment statique.
if (!hasPreviousSegment()) {
possible_dy = 0.0;
return(false);
}
// a ce stade, on a forcement un segment precedent
/// Si le segment precedent n'est pas statique, le mouvement est possible.
if (previous_segment -> hasPreviousSegment()) {
possible_dy = asked_dy;
return(true);
}
// a ce stade, le segment precedent est forcement statique
/// Si le segment precedent est horizontal, le mouvement est possible :
/// il induira la creation d'un segment vertical supplementaire.
if (previous_segment -> isHorizontal()) {
possible_dy = asked_dy;
return(true);
}
// a ce stade, le segment precedent est forcement vertical
// recupere quelques donnees
qreal prev_segment_first_y = previous_segment -> point1.y();
qreal first_y = point1.y();
/// Il se peut que le mouvement doive etre limite de facon a ce
/// que le segment statique conserve une taille minimale.
if (previous_segment -> length() > 0.0) {
if (first_y + asked_dy < prev_segment_first_y + 12.0) {
possible_dy = -(first_y - prev_segment_first_y - 12.0);
return(false);
} else {
possible_dy = asked_dy;
return(true);
}
} else {
if (first_y + asked_dy >= prev_segment_first_y - 12.0) {
possible_dy = prev_segment_first_y - 12.0 - first_y;
return(false);
} else {
possible_dy = asked_dy;
return(true);
}
}
}
/**
Permet de savoir s'il est possible de deplacer le second point du segment
sans creer d'incoherence. La valeur du mouvement maximum qu'il est possible de faire
sans incoherence est stockee dans le second parametre.
@param asked_dy La valeur du mouvement demande
@param possible_dy La valeur du mouvement possible (au maximum)
@return true si le mouvement est possible ; false s'il doit etre limite
*/
bool ConducerSegment::canMove2ndPointY(qreal asked_dy, qreal &possible_dy) {
Q_ASSERT_X(isHorizontal(), "ConducerSegment::canMove2ndPointY", "segment non horizontal");
/// On ne modifie jamais l'abscisse du second point d'un segment statique.
if (!hasNextSegment()) {
possible_dy = 0.0;
return(false);
}
// a ce stade, on a forcement un segment suivant
/// Si le segment suivant n'est pas statique, le mouvement est possible.
if (next_segment -> hasNextSegment()) {
possible_dy = asked_dy;
return(true);
}
// a ce stade, le segment suivant est forcement statique
/// Si le segment suivant est horizontal, le mouvement est possible :
/// il induira la creation d'un segment vertical supplementaire.
if (next_segment -> isHorizontal()) {
possible_dy = asked_dy;
return(true);
}
// a ce stade, le segment suivant est forcement vertical
// recupere quelques donnees
qreal next_segment_second_y = next_segment -> point2.y();
qreal second_y = point2.y();
/// Il se peut que le mouvement doive etre limite de facon a ce
/// que le segment statique conserve une taille minimale.
if (next_segment -> length() < 0.0) {
if (second_y + asked_dy < next_segment_second_y + 12.0) {
possible_dy = second_y - next_segment_second_y - 12.0;
return(false);
} else {
possible_dy = asked_dy;
return(true);
}
} else {
if (second_y + asked_dy >= next_segment_second_y - 12.0) {
possible_dy = next_segment_second_y - 12.0 - second_y;
return(false);
} else {
possible_dy = asked_dy;
return(true);
}
}
}
void ConducerSegment::moveX(qreal dx) {
if (isHorizontal()) return;
Q_ASSERT_X(isVertical(), "ConducerSegment::moveX", "segment non vertical");
bool has_prev_segment = hasPreviousSegment();
bool has_next_segment = hasNextSegment();
if (!has_prev_segment || !has_next_segment) return;
// determine si le mouvement demande doit etre limite et, le cas echeant, a quelle valeur il faut le limiter
qreal real_dx_for_1st_point = 0.0;
qreal real_dx_for_2nd_point = 0.0;
canMove1stPointX(dx, real_dx_for_1st_point);
canMove2ndPointX(dx, real_dx_for_2nd_point);
qreal final_movement = (dx <= 0.0) ? qMax(real_dx_for_1st_point, real_dx_for_2nd_point) : qMin(real_dx_for_1st_point, real_dx_for_2nd_point);
// applique le mouvement au premier point
if (has_prev_segment) {
point1.rx() += final_movement;
if (!previous_segment -> hasPreviousSegment() && previous_segment -> isVertical()) {
new ConducerSegment(
previous_segment -> point2,
point1,
previous_segment,
this
);
} else previous_segment -> setSecondPoint(point1);
}
// applique le mouvement au second point
if (has_next_segment) {
point2.rx() += final_movement;
if (!next_segment -> hasNextSegment() && next_segment -> isVertical()) {
new ConducerSegment(
point2,
next_segment -> point1,
this,
next_segment
);
} else next_segment -> setFirstPoint(point2);
}
}
void ConducerSegment::moveY(qreal dy) {
if (isVertical()) return;
Q_ASSERT_X(isHorizontal(), "ConducerSegment::moveY", "segment non horizontal");
bool has_prev_segment = hasPreviousSegment();
bool has_next_segment = hasNextSegment();
if (!has_prev_segment || !has_next_segment) return;
// determine si le mouvement demande doit etre limite et, le cas echeant, a quelle valeur il faut le limiter
qreal real_dy_for_1st_point = 0.0;
qreal real_dy_for_2nd_point = 0.0;
canMove1stPointY(dy, real_dy_for_1st_point);
canMove2ndPointY(dy, real_dy_for_2nd_point);
qreal final_movement = (dy <= 0.0) ? qMax(real_dy_for_1st_point, real_dy_for_2nd_point) : qMin(real_dy_for_1st_point, real_dy_for_2nd_point);
// applique le mouvement au premier point
if (has_prev_segment) {
point1.ry() += final_movement;
if (!previous_segment -> hasPreviousSegment() && previous_segment -> isHorizontal()) {
new ConducerSegment(
previous_segment -> point2,
point1,
previous_segment,
this
);
} else previous_segment -> setSecondPoint(point1);
}
// applique le mouvement au second point
if (has_next_segment) {
point2.ry() += final_movement;
if (!next_segment -> hasNextSegment() && next_segment -> isHorizontal()) {
new ConducerSegment(
point2,
next_segment -> point1,
this,
next_segment
);
} else next_segment -> setFirstPoint(point2);
}
}
/*
void ConducerSegment::moveY(qreal dy) {
if (isVertical()) return;
Q_ASSERT_X(isHorizontal(), "ConducerSegment::moveY", "segment non horizontal");
bool has_prev_segment = hasPreviousSegment();
bool has_next_segment = hasNextSegment();
if (!has_prev_segment || !has_next_segment) return;
// s'il y a un segment precedent
if (has_prev_segment) {
// et que celui-ci est statique,
if (!previous_segment -> hasPreviousSegment()) {
// on agit differemment selon que le segment statique est vertical...
if (previous_segment -> isVertical()) {
// auquel cas, on limite le deplacement
qreal real_dy;
/// @todo limiter le deplacement
real_dy = 0.0;
point1.ry() += real_dy;
previous_segment -> setSecondPoint(point1);
} else {
// ou horizontal : auquel cas, on ajoute un segment vertical
point1.ry() += dy;
new ConducerSegment(
previous_segment -> point2,
point1,
previous_segment,
this
);
}
} else {
// si le segment n'est pas statique, on applique le deplacement
point1.ry() += dy;
previous_segment -> setSecondPoint(point1);
}
}
// s'il y a un segment suivant
if (has_next_segment) {
// et que celui-ci est statique,
if (!next_segment -> hasNextSegment()) {
// on agit differemment selon que le segment statique est vertical...
if (next_segment -> isVertical()) {
// auquel cas, on limite le deplacement
qreal real_dy;
/// @todo limiter le deplacement
real_dy = 0.0;
point2.ry() += real_dy;
next_segment -> setFirstPoint(point2);
} else {
// ou horizontal : auquel cas, on ajoute un segment horizontal
point2.ry() += dy;
new ConducerSegment(
point2,
next_segment -> point1,
this,
next_segment
);
}
} else {
// si le segment n'est pas statique, on applique le deplacement
point2.ry() += dy;
next_segment -> setFirstPoint(point2);
}
}
}
*/
void ConducerSegment::setPreviousSegment(ConducerSegment *ps) {
previous_segment = ps;
if (hasPreviousSegment()) {
if (previousSegment() -> nextSegment() != this) previousSegment() -> setNextSegment(this);
}
}
void ConducerSegment::setNextSegment(ConducerSegment *ns) {
next_segment = ns;
if (hasNextSegment()) {
if (nextSegment() -> previousSegment() != this) nextSegment() -> setPreviousSegment(this);
}
}
ConducerSegment *ConducerSegment::previousSegment() {
return(previous_segment);
}
ConducerSegment *ConducerSegment::nextSegment() {
return(next_segment);
}
bool ConducerSegment::isVertical() {
return(point1.x() == point2.x());
}
bool ConducerSegment::isHorizontal() {
return(point1.y() == point2.y());
}
QPointF ConducerSegment::firstPoint() {
return(point1);
}
QPointF ConducerSegment::secondPoint() {
return(point2);
}
void ConducerSegment::setFirstPoint(QPointF p) {
point1 = p;
}
void ConducerSegment::setSecondPoint(QPointF p) {
point2 = p;
}
bool ConducerSegment::hasPreviousSegment() {
return(previous_segment != NULL);
}
bool ConducerSegment::hasNextSegment() {
return(next_segment != NULL);
}
QPointF ConducerSegment::middle() {
return(
QPointF(
(point1.x() + point2.x()) / 2.0,
(point1.y() + point2.y()) / 2.0
)
);
}
qreal ConducerSegment::length() {
if (isHorizontal()) {
return(secondPoint().x() - firstPoint().x());
} else {
return(secondPoint().y() - firstPoint().y());
}
}

43
conducersegment.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef CONDUCER_SEGMENT_H
#define CONDUCER_SEGMENT_H
#include <QPointF>
/**
Cette classe represente un segment de conducteur.
*/
class ConducerSegment {
// constructeurs et destructeur
public:
ConducerSegment(QPointF, QPointF, ConducerSegment * = NULL, ConducerSegment * = NULL);
~ConducerSegment();
// attributs
private:
ConducerSegment *previous_segment;
ConducerSegment *next_segment;
QPointF point1;
QPointF point2;
// methodes
public:
void moveX(qreal);
void moveY(qreal);
ConducerSegment *previousSegment();
ConducerSegment *nextSegment();
bool hasPreviousSegment();
bool hasNextSegment();
void setPreviousSegment(ConducerSegment *);
void setNextSegment(ConducerSegment *);
QPointF firstPoint();
QPointF secondPoint();
void setFirstPoint(QPointF);
void setSecondPoint(QPointF);
QPointF middle();
bool isHorizontal();
bool isVertical();
qreal length();
bool canMove1stPointX(qreal, qreal &);
bool canMove2ndPointX(qreal, qreal &);
bool canMove1stPointY(qreal, qreal &);
bool canMove2ndPointY(qreal, qreal &);
};
#endif

View File

@@ -19,7 +19,8 @@ HEADERS += aboutqet.h \
exportdialog.h \ exportdialog.h \
fixedelement.h \ fixedelement.h \
qetapp.h \ qetapp.h \
terminal.h terminal.h \
conducersegment.h
SOURCES += aboutqet.cpp \ SOURCES += aboutqet.cpp \
borderinset.cpp \ borderinset.cpp \
conducer.cpp \ conducer.cpp \
@@ -32,7 +33,8 @@ SOURCES += aboutqet.cpp \
fixedelement.cpp \ fixedelement.cpp \
main.cpp \ main.cpp \
qetapp.cpp \ qetapp.cpp \
terminal.cpp terminal.cpp \
conducersegment.cpp
RESOURCES += qelectrotech.qrc RESOURCES += qelectrotech.qrc
TRANSLATIONS += lang/qet_en.ts lang/qt_fr.ts TRANSLATIONS += lang/qet_en.ts lang/qt_fr.ts
QT += xml QT += xml

View File

@@ -170,8 +170,10 @@ void Terminal::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) {
t.setColor(couleur_hovered); t.setColor(couleur_hovered);
p -> setPen(t); p -> setPen(t);
p -> setBrush(couleur_hovered); p -> setBrush(couleur_hovered);
if (hovered) p -> drawEllipse(((int)f.x())-2, ((int)f.y())-2, 5, 5); if (hovered) {
else p -> drawPoint(f); p -> setRenderHint(QPainter::Antialiasing, true);
p -> drawEllipse(((int)f.x())-2, ((int)f.y())-2, 5, 5);
} else p -> drawPoint(f);
p -> restore(); p -> restore();
} }