mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2025-12-20 16:20:52 +01:00
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:
265
conducer.cpp
265
conducer.cpp
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
21
conducer.h
21
conducer.h
@@ -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
92
conducerprofile.cpp
Normal 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
34
conducerprofile.h
Normal 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
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
42
conducersegmentprofile.h
Normal 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
|
||||||
@@ -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
1
qet.h
@@ -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 &);
|
||||||
|
|||||||
Reference in New Issue
Block a user