Implementation d'un nouvel algorithme de modification des conducteurs

git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@125 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
xavierqet
2007-09-20 20:16:08 +00:00
parent 86f62aa972
commit 109476589b
9 changed files with 375 additions and 94 deletions

View File

@@ -1,6 +1,7 @@
#include <QtDebug> #include <QtDebug>
#include "conducer.h" #include "conducer.h"
#include "conducersegment.h" #include "conducersegment.h"
#include "conducersegmentprofile.h"
#include "element.h" #include "element.h"
#define PR(x) qDebug() << #x " = " << x; #define PR(x) qDebug() << #x " = " << x;
@@ -15,17 +16,23 @@ QBrush Conducer::conducer_brush = QBrush();
@param parent Element parent du conducteur (0 par defaut) @param parent Element parent du conducteur (0 par defaut)
@param scene QGraphicsScene auquelle appartient le conducteur @param scene QGraphicsScene auquelle appartient le conducteur
*/ */
Conducer::Conducer(Terminal *p1, Terminal* p2, Element *parent, QGraphicsScene *scene) : QGraphicsPathItem(parent, scene) { Conducer::Conducer(Terminal *p1, Terminal* p2, Element *parent, QGraphicsScene *scene) :
// bornes que le conducteur relie QGraphicsPathItem(parent, scene),
terminal1 = p1; terminal1(p1),
terminal2 = p2; terminal2(p2),
destroyed(false),
segments(NULL),
previous_z_value(zValue()),
modified_path(false),
has_to_save_profile(false)
{
// ajout du conducteur a la liste de conducteurs de chacune des deux bornes // ajout du conducteur a la liste de conducteurs de chacune des deux bornes
bool ajout_p1 = terminal1 -> addConducer(this); bool ajout_p1 = terminal1 -> addConducer(this);
bool ajout_p2 = terminal2 -> addConducer(this); bool ajout_p2 = terminal2 -> addConducer(this);
// 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;
modified_path = false;
// attributs de dessin par defaut (communs a tous les conducteurs) // attributs de dessin par defaut (communs a tous les conducteurs)
if (!pen_and_brush_initialized) { if (!pen_and_brush_initialized) {
conducer_pen.setJoinStyle(Qt::MiterJoin); conducer_pen.setJoinStyle(Qt::MiterJoin);
@@ -37,12 +44,11 @@ Conducer::Conducer(Terminal *p1, Terminal* p2, Element *parent, QGraphicsScene *
conducer_brush.setStyle(Qt::NoBrush); conducer_brush.setStyle(Qt::NoBrush);
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);
setAcceptsHoverEvents(true); setAcceptsHoverEvents(true);
previous_z_value = zValue();
// ajout du champ de texte editable // ajout du champ de texte editable
text_item = new QGraphicsTextItem(); text_item = new QGraphicsTextItem();
@@ -148,51 +154,125 @@ void Conducer::segmentsToPath() {
@param o2 Orientation de la borne 2 @param o2 Orientation de la borne 2
*/ */
void Conducer::priv_modifieConducer(const QPointF &p1, QET::Orientation, const QPointF &p2, QET::Orientation) { void Conducer::priv_modifieConducer(const QPointF &p1, QET::Orientation, const QPointF &p2, QET::Orientation) {
Q_ASSERT_X(nbSegments() > 1, "priv_modifieConducer", "pas de points a modifier"); // determine le nombre de segments horizontaux et verticaux
uint nb_horiz_segments = conducer_profile.nbSegments(QET::Horizontal);
uint nb_verti_segments = conducer_profile.nbSegments(QET::Vertical);
// recupere les dernieres coordonnees connues des bornes Q_ASSERT_X(nb_horiz_segments + nb_verti_segments > 1, "Conducer::priv_modifieConducer", "pas de points a modifier");
QPointF old_p1 = mapFromScene(terminal1 -> amarrageConducer()); Q_ASSERT_X(!conducer_profile.isNull(), "Conducer::priv_modifieConducer", "pas de profil utilisable");
QPointF old_p2 = mapFromScene(terminal2 -> amarrageConducer());
// recupere les coordonnees fournies des bornes // recupere les coordonnees fournies des bornes
QPointF new_p1 = mapFromScene(p1); QPointF new_p1 = mapFromScene(p1);
QPointF new_p2 = mapFromScene(p2); QPointF new_p2 = mapFromScene(p2);
QRectF new_rect = QRectF(new_p1, new_p2);
// les distances horizontales et verticales entre les anciennes bornes // recupere la largeur et la hauteur du profil
// sont stockees dans orig_dist_2_terms_x et orig_dist_2_terms_y qreal profile_width = conducer_profile.width();
qreal profile_height = conducer_profile.height();
// calcule les distances horizontales et verticales entre les nouvelles bornes // calcule les differences verticales et horizontales a appliquer
qreal new_dist_2_terminals_x = new_p2.x() - new_p1.x(); qreal h_diff = (qAbs(new_rect.width()) - qAbs(profile_width) ) * getSign(profile_width);
qreal new_dist_2_terminals_y = new_p2.y() - new_p1.y(); qreal v_diff = (qAbs(new_rect.height()) - qAbs(profile_height)) * getSign(profile_height);
// applique les differences aux segments
QHash<ConducerSegmentProfile *, qreal> segments_lengths;
segments_lengths.unite(shareOffsetBetweenSegments(h_diff, conducer_profile.horizontalSegments()));
segments_lengths.unite(shareOffsetBetweenSegments(v_diff, conducer_profile.verticalSegments()));
// en deduit egalement les coefficients d'inversion (-1 pour une inversion, +1 pour conserver le meme sens)
int horiz_coeff = getCoeff(new_rect.width(), profile_width);
int verti_coeff = getCoeff(new_rect.height(), profile_height);
// en deduit les coefficients de "redimensionnement"
qreal coeff_x = new_dist_2_terminals_x / orig_dist_2_terms_x;
qreal coeff_y = new_dist_2_terminals_y / orig_dist_2_terms_y;
/*
if (!orig_dist_2_terms_x || !orig_dist_2_terms_y) {
qDebug() << "ca va planter";
PR(coeff_x)
PR(coeff_y)
}
*/
// genere les nouveaux points // genere les nouveaux points
int limite = moves_x.size() - 1;
int coeff = type_trajet_x ? 1 : -1;
QList<QPointF> points; QList<QPointF> points;
points << (type_trajet_x ? new_p1 : new_p2); points << new_p1;
for (int i = 0 ; i < limite ; ++ i) { int limit = conducer_profile.segments.count() - 1;
for (int i = 0 ; i < limit ; ++ i) {
// dernier point
QPointF previous_point = points.last(); QPointF previous_point = points.last();
points << QPointF (
previous_point.x() + (moves_x.at(i) * coeff_x * coeff), // profil de segment de conducteur en cours
previous_point.y() + (moves_y.at(i) * coeff_y * coeff) ConducerSegmentProfile *csp = conducer_profile.segments.at(i);
);
// coefficient et offset a utiliser pour ce point
qreal coeff = csp -> isHorizontal ? horiz_coeff : verti_coeff;
qreal offset_applied = segments_lengths[csp];
// applique l'offset et le coeff au point
if (csp -> isHorizontal) {
points << QPointF (
previous_point.x() + (coeff * offset_applied),
previous_point.y()
);
} else {
points << QPointF (
previous_point.x(),
previous_point.y() + (coeff * offset_applied)
);
}
} }
points << (type_trajet_x ? new_p2 : new_p1); points << new_p2;
pointsToSegments(points); pointsToSegments(points);
segmentsToPath(); segmentsToPath();
} }
/**
@param offset Longueur a repartir entre les segments
@param segments_list Segments sur lesquels il faut repartir la longueur
@param precision seuil en-deca duquel on considere qu'il ne reste rien a repartir
*/
QHash<ConducerSegmentProfile *, qreal> Conducer::shareOffsetBetweenSegments(
const qreal &offset,
const QList<ConducerSegmentProfile *> &segments_list,
const qreal &precision
) const {
// construit le QHash qui sera retourne
QHash<ConducerSegmentProfile *, qreal> segments_hash;
foreach(ConducerSegmentProfile *csp, segments_list) {
segments_hash.insert(csp, csp -> length);
}
// memorise le signe de la longueur de chaque segement
QHash<ConducerSegmentProfile *, int> segments_signs;
foreach(ConducerSegmentProfile *csp, segments_hash.keys()) {
segments_signs.insert(csp, getSign(csp -> length));
}
//qDebug() << "repartition d'un offset de" << offset << "px sur" << segments_list.count() << "segments";
// repartit l'offset sur les segments
qreal remaining_offset = offset;
while (remaining_offset > precision || remaining_offset < -precision) {
// recupere le nombre de segments differents ayant une longueur non nulle
uint segments_count = 0;
foreach(ConducerSegmentProfile *csp, segments_hash.keys()) if (segments_hash[csp]) ++ segments_count;
//qDebug() << " remaining_offset =" << remaining_offset;
qreal local_offset = remaining_offset / segments_count;
//qDebug() << " repartition d'un offset local de" << local_offset << "px sur" << segments_count << "segments";
remaining_offset = 0.0;
foreach(ConducerSegmentProfile *csp, segments_hash.keys()) {
// ignore les segments de longueur nulle
if (!segments_hash[csp]) continue;
// applique l'offset au segment
//qreal segment_old_length = segments_hash[csp];
segments_hash[csp] += local_offset;
// (la longueur du segment change de signe) <=> (le segment n'a pu absorbe tout l'offset)
if (segments_signs[csp] != getSign(segments_hash[csp])) {
// on remet le trop-plein dans la reserve d'offset
remaining_offset += qAbs(segments_hash[csp]) * getSign(local_offset);
//qDebug() << " trop-plein de" << qAbs(segments_hash[csp]) * getSign(local_offset) << "remaining_offset =" << remaining_offset;
segments_hash[csp] = 0.0;
} else {
//qDebug() << " offset local de" << local_offset << "accepte";
}
}
}
return(segments_hash);
}
/** /**
Calcule un trajet "par defaut" pour le conducteur Calcule un trajet "par defaut" pour le conducteur
@param p1 Coordonnees du point d'amarrage de la borne 1 @param p1 Coordonnees du point d'amarrage de la borne 1
@@ -207,7 +287,6 @@ void Conducer::priv_calculeConducer(const QPointF &p1, QET::Orientation o1, cons
// s'assure qu'il n'y a ni points // s'assure qu'il n'y a ni points
QList<QPointF> points; QList<QPointF> points;
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);
sp2 = mapFromScene(p2); sp2 = mapFromScene(p2);
@@ -282,6 +361,13 @@ void Conducer::priv_calculeConducer(const QPointF &p1, QET::Orientation o1, cons
// prolongement de la borne d'arrivee // prolongement de la borne d'arrivee
points << arrivee0; points << arrivee0;
// inverse eventuellement l'ordre des points afin que le trajet soit exprime de la borne 1 vers la borne 2
if (newp1.x() > newp2.x()) {
QList<QPointF> points2;
for (int i = points.size() - 1 ; i >= 0 ; -- i) points2 << points.at(i);
points = points2;
}
pointsToSegments(points); pointsToSegments(points);
segmentsToPath(); segmentsToPath();
} }
@@ -480,7 +566,7 @@ void Conducer::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
// application du deplacement // application du deplacement
modified_path = true; modified_path = true;
updatePoints(); has_to_save_profile = true;
segmentsToPath(); segmentsToPath();
calculateTextItemPosition(); calculateTextItemPosition();
} }
@@ -496,6 +582,10 @@ void Conducer::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
// clic gauche // clic gauche
moving_point = false; moving_point = false;
moving_segment = false; moving_segment = false;
if (has_to_save_profile) {
saveProfile();
has_to_save_profile = false;
}
setZValue(previous_z_value); setZValue(previous_z_value);
QGraphicsPathItem::mouseReleaseEvent(e); QGraphicsPathItem::mouseReleaseEvent(e);
calculateTextItemPosition(); calculateTextItemPosition();
@@ -577,24 +667,6 @@ QPainterPath Conducer::shape() const {
return(area); return(area);
} }
/**
Met à jour deux listes de reels.
*/
void Conducer::updatePoints() {
QList<QPointF> points = segmentsToPoints();
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();
}
/** /**
Renvoie une valeur donnee apres l'avoir bornee entre deux autres valeurs, Renvoie une valeur donnee apres l'avoir bornee entre deux autres valeurs,
en y ajoutant une marge interne. en y ajoutant une marge interne.
@@ -603,8 +675,8 @@ void Conducer::updatePoints() {
@param bound2 borne 2 @param bound2 borne 2
@return La valeur bornee @return La valeur bornee
*/ */
qreal Conducer::conducer_bound(qreal tobound, qreal bound1, qreal bound2) { qreal Conducer::conducer_bound(qreal tobound, qreal bound1, qreal bound2, qreal space) {
qreal space = 5.0; qDebug() << "will bound" << tobound << "between" << bound1 << "and" << bound2 ;
if (bound1 < bound2) { if (bound1 < bound2) {
return(qBound(bound1 + space, tobound, bound2 - space)); return(qBound(bound1 + space, tobound, bound2 - space));
} else { } else {
@@ -625,15 +697,15 @@ qreal Conducer::conducer_bound(qreal tobound, qreal bound, bool positive) {
} }
/** /**
@param type Type de Segments
@return Le nombre de segments composant le conducteur. @return Le nombre de segments composant le conducteur.
*/ */
int Conducer::nbSegments() const { uint Conducer::nbSegments(QET::ConducerSegmentType type) const {
if (segments == NULL) return(0); QList<ConducerSegment *> segments_list = segmentsList();
int nb_seg = 1; if (type == QET::Both) return(segments_list.count());
ConducerSegment *segment = segments; uint nb_seg = 0;
while (segment -> hasNextSegment()) { foreach(ConducerSegment *conducer_segment, segments_list) {
++ nb_seg; if (conducer_segment -> type() == type) ++ nb_seg;
segment = segment -> nextSegment();
} }
return(nb_seg); return(nb_seg);
} }
@@ -740,15 +812,14 @@ bool Conducer::fromXml(QDomElement &e) {
// s'il n'y a pas de segments, on renvoie true // s'il n'y a pas de segments, on renvoie true
if (!segments_x.size()) return(true); if (!segments_x.size()) return(true);
// les longueurs recueillies doivent etre coherentes avec les positions des bornes // les longueurs recueillies doivent etre coherentes avec les positions des bornes
qreal width = 0.0, height = 0.0; qreal width = 0.0, height = 0.0;
foreach (qreal t, segments_x) width += t; foreach (qreal t, segments_x) width += t;
foreach (qreal t, segments_y) height += t; foreach (qreal t, segments_y) height += t;
QPointF t1 = terminal1 -> amarrageConducer(); QPointF t1 = terminal1 -> amarrageConducer();
QPointF t2 = terminal2 -> amarrageConducer(); QPointF t2 = terminal2 -> amarrageConducer();
qreal expected_width = qAbs(t2.x() - t1.x()); qreal expected_width = t2.x() - t1.x();
qreal expected_height = qAbs(t2.y() - t1.y()); qreal expected_height = t2.y() - t1.y();
qreal precision = std::numeric_limits<qreal>::epsilon(); qreal precision = std::numeric_limits<qreal>::epsilon();
if ( if (
expected_width > width + precision ||\ expected_width > width + precision ||\
@@ -760,7 +831,7 @@ bool Conducer::fromXml(QDomElement &e) {
/* on recree les segments a partir des donnes XML */ /* on recree les segments a partir des donnes XML */
// cree la liste de points // cree la liste de points
QList<QPointF> points_list; QList<QPointF> points_list;
points_list << (t1.x() < t2.x() ? t1 : t2); points_list << t1;
for (int i = 0 ; i < segments_x.size() ; ++ i) { for (int i = 0 ; i < segments_x.size() ; ++ i) {
points_list << QPointF( points_list << QPointF(
points_list.last().x() + segments_x.at(i), points_list.last().x() + segments_x.at(i),
@@ -772,11 +843,7 @@ bool Conducer::fromXml(QDomElement &e) {
// initialise divers parametres lies a la modification des conducteurs // initialise divers parametres lies a la modification des conducteurs
modified_path = true; modified_path = true;
moves_x = segments_x; saveProfile();
moves_y = segments_y;
type_trajet_x = t1.x() < t2.x();
orig_dist_2_terms_x = points_list.at(points_list.size() - 1).x() - points_list.at(0).x();
orig_dist_2_terms_y = points_list.at(points_list.size() - 1).y() - points_list.at(0).y();
segmentsToPath(); segmentsToPath();
return(true); return(true);
@@ -800,20 +867,29 @@ QDomElement Conducer::toXml(QDomDocument &d, QHash<Terminal *, int> &table_adr_i
if (!modified_path) return(e); if (!modified_path) return(e);
// parcours et export des segments // parcours et export des segments
ConducerSegment *segment = segments;
QDomElement current_segment; QDomElement current_segment;
while (segment -> hasNextSegment()) { foreach(ConducerSegment *segment, segmentsList()) {
current_segment = d.createElement("segment"); current_segment = d.createElement("segment");
current_segment.setAttribute("orientation", segment -> isHorizontal() ? "horizontal" : "vertical"); current_segment.setAttribute("orientation", segment -> isHorizontal() ? "horizontal" : "vertical");
current_segment.setAttribute("length", segment -> length()); current_segment.setAttribute("length", segment -> length());
e.appendChild(current_segment); e.appendChild(current_segment);
}
return(e);
}
/// @return les segments de ce conducteur
const QList<ConducerSegment *> Conducer::segmentsList() const {
if (segments == NULL) return(QList<ConducerSegment *>());
QList<ConducerSegment *> segments_vector;
ConducerSegment *segment = segments;
while (segment -> hasNextSegment()) {
segments_vector << segment;
segment = segment -> nextSegment(); segment = segment -> nextSegment();
} }
current_segment = d.createElement("segment"); segments_vector << segment;
current_segment.setAttribute("orientation", segment -> isHorizontal() ? "horizontal" : "vertical"); return(segments_vector);
current_segment.setAttribute("length", segment -> length());
e.appendChild(current_segment);
return(e);
} }
/** /**
@@ -859,3 +935,28 @@ ConducerSegment *Conducer::middleSegment() {
void Conducer::calculateTextItemPosition() { void Conducer::calculateTextItemPosition() {
text_item -> setPos(middleSegment() -> middle()); text_item -> setPos(middleSegment() -> middle());
} }
/**
Sauvegarde le profil courant du conducteur pour l'utiliser ulterieurement
dans priv_modifieConducer.
*/
void Conducer::saveProfile() {
conducer_profile = ConducerProfile(this);
}
/**
@param value1 Premiere valeur
@param value2 Deuxieme valeur
@return 1 si les deux valeurs sont de meme signe, -1 sinon
*/
int Conducer::getCoeff(const qreal &value1, const qreal &value2) {
return(getSign(value1) * getSign(value2));
}
/**
@param value valeur
@return 1 si valeur est negatif, 1 s'il est positif ou nul
*/
int Conducer::getSign(const qreal &value) {
return(value < 0 ? -1 : 1);
}

View File

@@ -2,6 +2,7 @@
#define CONDUCTEUR_H #define CONDUCTEUR_H
#include <QtGui> #include <QtGui>
#include "terminal.h" #include "terminal.h"
#include "conducerprofile.h"
class ConducerSegment; class ConducerSegment;
class Element; class Element;
/** /**
@@ -20,6 +21,7 @@ class Conducer : public QGraphicsPathItem {
// attributs // attributs
public: public:
enum { Type = UserType + 1001 }; enum { Type = UserType + 1001 };
///Premiere borne a laquelle le fil est rattache ///Premiere borne a laquelle le fil est rattache
Terminal *terminal1; Terminal *terminal1;
///Deuxieme borne a laquelle le fil est rattache ///Deuxieme borne a laquelle le fil est rattache
@@ -30,11 +32,6 @@ class Conducer : public QGraphicsPathItem {
bool destroyed; bool destroyed;
QGraphicsTextItem *text_item; QGraphicsTextItem *text_item;
ConducerSegment *segments; ConducerSegment *segments;
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; QPointF press_point;
bool moving_point; bool moving_point;
bool moving_segment; bool moving_segment;
@@ -42,6 +39,8 @@ class Conducer : public QGraphicsPathItem {
qreal previous_z_value; qreal previous_z_value;
ConducerSegment *moved_segment; ConducerSegment *moved_segment;
bool modified_path; bool modified_path;
bool has_to_save_profile;
ConducerProfile conducer_profile;
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;
@@ -61,6 +60,7 @@ class Conducer : public QGraphicsPathItem {
static bool valideXml(QDomElement &); static bool valideXml(QDomElement &);
bool fromXml(QDomElement &); bool fromXml(QDomElement &);
QDomElement toXml(QDomDocument &, QHash<Terminal *, int> &) const; QDomElement toXml(QDomDocument &, QHash<Terminal *, int> &) const;
const QList<ConducerSegment *> segmentsList() const;
protected: protected:
void mousePressEvent(QGraphicsSceneMouseEvent *); void mousePressEvent(QGraphicsSceneMouseEvent *);
@@ -70,16 +70,19 @@ class Conducer : public QGraphicsPathItem {
private: private:
void segmentsToPath(); void segmentsToPath();
void updatePoints(); void saveProfile();
void priv_calculeConducer(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation); void priv_calculeConducer(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation);
void priv_modifieConducer(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation); void priv_modifieConducer(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation);
int nbSegments() const; uint nbSegments(QET::ConducerSegmentType = QET::Both) const;
QList<QPointF> segmentsToPoints() const; QList<QPointF> segmentsToPoints() const;
void pointsToSegments(QList<QPointF>); void pointsToSegments(QList<QPointF>);
bool hasClickedOn(QPointF, QPointF) const; bool hasClickedOn(QPointF, QPointF) const;
void calculateTextItemPosition(); void calculateTextItemPosition();
static int getCoeff(const qreal &, const qreal &);
static int getSign(const qreal &);
QHash<ConducerSegmentProfile *, qreal> shareOffsetBetweenSegments(const qreal &offset, const QList<ConducerSegmentProfile *> &, const qreal & = 0.01) const;
static QPointF extendTerminal(const QPointF &, QET::Orientation, qreal = 12.0); static QPointF extendTerminal(const QPointF &, QET::Orientation, qreal = 12.0);
static qreal conducer_bound(qreal tobound, qreal bound1, qreal bound2); static qreal conducer_bound(qreal, qreal, qreal, qreal = 0.0);
static qreal conducer_bound(qreal tobound, qreal bound, bool positive); static qreal conducer_bound(qreal, qreal, bool);
}; };
#endif #endif

92
conducerprofile.cpp Normal file
View File

@@ -0,0 +1,92 @@
#include "conducerprofile.h"
#include "conducer.h"
#include "conducersegmentprofile.h"
/// Constructeur
ConducerProfile::ConducerProfile() {
}
/**
Constructeur
@param Conducer conducteur dont il faut extraire le profil
*/
ConducerProfile::ConducerProfile(Conducer *conducer) {
foreach(ConducerSegment *conducer_segment, conducer -> segmentsList()) {
segments << new ConducerSegmentProfile(conducer_segment);
}
beginOrientation = conducer -> terminal1 -> orientation();
endOrientation = conducer -> terminal2 -> orientation();
}
/// destructeur
ConducerProfile::~ConducerProfile() {
}
/// @return true si le profil est nul
bool ConducerProfile::isNull() const {
return(segments.isEmpty());
}
/// @return la largeur occupee par le conducteur
qreal ConducerProfile::width() const {
qreal width = 0.0;
foreach(ConducerSegmentProfile *csp, segments) {
if (csp -> isHorizontal) width += csp -> length;
}
return(width);
}
/// @return la hauteur occupee par le conducteur
qreal ConducerProfile::height() const{
qreal height = 0.0;
foreach(ConducerSegmentProfile *csp, segments) {
if (!csp -> isHorizontal) height += csp -> length;
}
return(height);
}
/**
@param type Type de Segments
@return Le nombre de segments composant le conducteur.
*/
uint ConducerProfile::nbSegments(QET::ConducerSegmentType type) const {
if (type == QET::Both) return(segments.count());
uint nb_seg = 0;
foreach(ConducerSegmentProfile *csp, segments) {
if (type == QET::Horizontal && csp -> isHorizontal) ++ nb_seg;
else if (type == QET::Vertical && !csp -> isHorizontal) ++ nb_seg;
}
return(nb_seg);
}
/// @return les segments horizontaux de ce profil
QList<ConducerSegmentProfile *> ConducerProfile::horizontalSegments() {
QList<ConducerSegmentProfile *> segments_list;
foreach(ConducerSegmentProfile *csp, segments) {
if (csp -> isHorizontal) segments_list << csp;
}
return(segments_list);
}
/// @return les segments verticaux de ce profil
QList<ConducerSegmentProfile *> ConducerProfile::verticalSegments() {
QList<ConducerSegmentProfile *> segments_list;
foreach(ConducerSegmentProfile *csp, segments) {
if (!csp -> isHorizontal) segments_list << csp;
}
return(segments_list);
}
/**
Permet de debugger un profil de conducteur
@param d Object QDebug a utiliser pour l'affichage des informations de debug
@param t Profil de conducteur a debugger
*/
QDebug &operator<<(QDebug d, ConducerProfile &t) {
d << "ConducerProfile {";
foreach(ConducerSegmentProfile *csp, t.segments) {
d << "CSP" << (csp -> isHorizontal ? "horizontal" : "vertical") << ":" << csp -> length << ",";
}
d << "}";
return(d.space());
}

34
conducerprofile.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef CONDUCER_PROFILE_H
#define CONDUCER_PROFILE_H
#include <QList>
#include "qet.h"
class Conducer;
class ConducerSegmentProfile;
/**
Cette classe contient le profil (= les caracteristiques essentielles) d'un
conducteur.
*/
class ConducerProfile {
public:
// constructeurs, destructeur
ConducerProfile();
ConducerProfile(Conducer *conducer);
virtual ~ConducerProfile();
// attributs
public:
QList<ConducerSegmentProfile *> segments;
QET::Orientation beginOrientation;
QET::Orientation endOrientation;
// methodes
public:
bool isNull() const;
qreal width() const;
qreal height() const;
uint nbSegments(QET::ConducerSegmentType) const;
QList<ConducerSegmentProfile *> horizontalSegments();
QList<ConducerSegmentProfile *> verticalSegments();
};
QDebug &operator<<(QDebug d, ConducerProfile &);
#endif

View File

@@ -25,7 +25,6 @@ ConducerSegment::ConducerSegment(
Destructeur - Relie le segment precedent au suivant Destructeur - Relie le segment precedent au suivant
*/ */
ConducerSegment::~ConducerSegment() { ConducerSegment::~ConducerSegment() {
//qDebug() << "~ConducerSegment()" << (void *)this;
if (hasPreviousSegment()) previousSegment() -> setNextSegment(nextSegment()); if (hasPreviousSegment()) previousSegment() -> setNextSegment(nextSegment());
if (hasNextSegment()) nextSegment() -> setPreviousSegment(previousSegment()); if (hasNextSegment()) nextSegment() -> setPreviousSegment(previousSegment());
} }
@@ -494,3 +493,7 @@ qreal ConducerSegment::length() const {
return(secondPoint().y() - firstPoint().y()); return(secondPoint().y() - firstPoint().y());
} }
} }
QET::ConducerSegmentType ConducerSegment::type() const {
return(isHorizontal() ? QET::Horizontal : QET::Vertical);
}

View File

@@ -1,6 +1,7 @@
#ifndef CONDUCER_SEGMENT_H #ifndef CONDUCER_SEGMENT_H
#define CONDUCER_SEGMENT_H #define CONDUCER_SEGMENT_H
#include <QPointF> #include <QPointF>
#include "qet.h"
/** /**
Cette classe represente un segment de conducteur. Cette classe represente un segment de conducteur.
*/ */
@@ -41,6 +42,7 @@ class ConducerSegment {
QPointF middle() const; QPointF middle() const;
bool isHorizontal() const; bool isHorizontal() const;
bool isVertical() const; bool isVertical() const;
QET::ConducerSegmentType type() const;
qreal length() const; qreal length() const;
bool canMove1stPointX(const qreal &, qreal &) const; bool canMove1stPointX(const qreal &, qreal &) const;
bool canMove2ndPointX(const qreal &, qreal &) const; bool canMove2ndPointX(const qreal &, qreal &) const;

42
conducersegmentprofile.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef CONDUCER_SEGMENT_PROFILE_H
#define CONDUCER_SEGMENT_PROFILE_H
#include <QtCore>
#include "conducersegment.h"
/**
Cette classe contient le profil (= les caracteristiques essentielles) d'un
segment de conducteur.
*/
class ConducerSegmentProfile {
// constructeurs, destructeur
public:
/**
Constructeur
@param l longueur du segment
@param ori true si le segment est horizontal, false s'il est vertical
*/
ConducerSegmentProfile(qreal l, bool ori = true) :
length(l),
isHorizontal(ori)
{
}
/**
Constructeur
@param segment ConducerSegment dont il faut extraire le profil
*/
ConducerSegmentProfile(ConducerSegment *segment) :
length(segment -> length()),
isHorizontal(segment -> isHorizontal())
{
}
/// Destructeur
virtual ~ConducerSegmentProfile() {
}
// attributs
public:
qreal length; /// longueur du segment
bool isHorizontal; /// orientation du segment
};
#endif

View File

@@ -60,7 +60,9 @@ HEADERS += aboutqet.h \
editor/texteditor.h \ editor/texteditor.h \
editor/textfieldeditor.h \ editor/textfieldeditor.h \
elementscategorydeleter.h \ elementscategorydeleter.h \
elementdeleter.h elementdeleter.h \
conducersegmentprofile.h \
conducerprofile.h
SOURCES += aboutqet.cpp \ SOURCES += aboutqet.cpp \
borderinset.cpp \ borderinset.cpp \
conducer.cpp \ conducer.cpp \
@@ -114,7 +116,8 @@ SOURCES += aboutqet.cpp \
editor/texteditor.cpp \ editor/texteditor.cpp \
editor/textfieldeditor.cpp \ editor/textfieldeditor.cpp \
elementscategorydeleter.cpp \ elementscategorydeleter.cpp \
elementdeleter.cpp elementdeleter.cpp \
conducerprofile.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

1
qet.h
View File

@@ -8,6 +8,7 @@
*/ */
namespace QET { namespace QET {
enum Orientation {North, East, South, West}; enum Orientation {North, East, South, West};
enum ConducerSegmentType { Horizontal = 1, Vertical = 2, Both = 3 };
QET::Orientation nextOrientation(QET::Orientation); QET::Orientation nextOrientation(QET::Orientation);
QET::Orientation previousOrientation(QET::Orientation); QET::Orientation previousOrientation(QET::Orientation);
QET::Orientation orientationFromString(const QString &); QET::Orientation orientationFromString(const QString &);