1 /*
2 Copyright 2006-2019 The QElectroTech Team
3 This file is part of QElectroTech.
4
5 QElectroTech is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 QElectroTech is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "partline.h"
19 #include <cmath>
20 #include "elementscene.h"
21 #include "QPropertyUndoCommand/qpropertyundocommand.h"
22 #include "QetGraphicsItemModeler/qetgraphicshandleritem.h"
23
24
25 /**
26 * @brief PartLine::PartLine
27 * Constructor
28 * @param editor : QETElementEditor of this part
29 * @param parent : parent item
30 */
PartLine(QETElementEditor * editor,QGraphicsItem * parent)31 PartLine::PartLine(QETElementEditor *editor, QGraphicsItem *parent) :
32 CustomElementGraphicPart(editor, parent),
33 first_end(Qet::None),
34 first_length(1.5),
35 second_end(Qet::None),
36 second_length(1.5),
37 m_undo_command(nullptr)
38 {}
39
40 /// Destructeur
~PartLine()41 PartLine::~PartLine()
42 {
43 if(m_undo_command)
44 delete m_undo_command;
45
46 removeHandler();
47 }
48
49 /**
50 * @brief PartLine::requiredLengthForEndType
51 * @param end_type
52 * @return the number of "length" needed to draw a extremity of type Qet::EndType.
53 */
requiredLengthForEndType(const Qet::EndType & end_type)54 uint PartLine::requiredLengthForEndType(const Qet::EndType &end_type)
55 {
56 uint length_count_required = 0;
57
58 if (end_type == Qet::Circle || end_type == Qet::Diamond)
59 length_count_required = 2;
60 else if (end_type == Qet::Simple || end_type == Qet::Triangle)
61 length_count_required = 1;
62
63 return(length_count_required);
64 }
65
66 /**
67 * @brief PartLine::paint
68 * Draw this line
69 * @param painter
70 * @param options
71 * @param widget
72 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * options,QWidget * widget)73 void PartLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget)
74 {
75 Q_UNUSED(widget);
76 if (isUseless()) return;
77
78 painter->save();
79 applyStylesToQPainter(*painter);
80 QPen t = painter -> pen();
81 t.setJoinStyle(Qt::MiterJoin);
82 t.setCosmetic(options && options -> levelOfDetail < 1.0);
83
84 if (isSelected()) t.setColor(Qt::red);
85
86 painter -> setPen(t);
87
88 if (first_end || second_end)
89 painter -> drawPath(path());
90 else
91 painter -> drawLine(m_line);
92
93 if (m_hovered)
94 drawShadowShape(painter);
95
96 painter->restore();
97 }
98
99 /**
100 * @brief PartLine::toXml
101 * Export this line in xml
102 * @param xml_document : Xml document to use for create the xml element.
103 * @return an xml element that describe this line
104 */
toXml(QDomDocument & xml_document) const105 const QDomElement PartLine::toXml(QDomDocument &xml_document) const
106 {
107 QPointF p1(sceneP1());
108 QPointF p2(sceneP2());
109
110 QDomElement xml_element = xml_document.createElement("line");
111 xml_element.setAttribute("x1", QString("%1").arg(p1.x()));
112 xml_element.setAttribute("y1", QString("%1").arg(p1.y()));
113 xml_element.setAttribute("x2", QString("%1").arg(p2.x()));
114 xml_element.setAttribute("y2", QString("%1").arg(p2.y()));
115 xml_element.setAttribute("end1", Qet::endTypeToString(first_end));
116 xml_element.setAttribute("length1", QString("%1").arg(first_length));
117 xml_element.setAttribute("end2", Qet::endTypeToString(second_end));
118 xml_element.setAttribute("length2", QString("%1").arg(second_length));
119
120 stylesToXml(xml_element);
121 return(xml_element);
122 }
123
124 /**
125 * @brief PartLine::fromXml
126 * Import the properties of this line from a xml element.
127 * @param qde : Xml document to use
128 */
fromXml(const QDomElement & qde)129 void PartLine::fromXml(const QDomElement &qde) {
130 stylesFromXml(qde);
131 m_line = QLineF(mapFromScene(qde.attribute("x1", "0").toDouble(),
132 qde.attribute("y1", "0").toDouble()),
133 mapFromScene(qde.attribute("x2", "0").toDouble(),
134 qde.attribute("y2", "0").toDouble()));
135
136 first_end = Qet::endTypeFromString(qde.attribute("end1"));
137 first_length = qde.attribute("length1", "1.5").toDouble();
138 second_end = Qet::endTypeFromString(qde.attribute("end2"));
139 second_length = qde.attribute("length2", "1.5").toDouble();
140 }
141
142 /**
143 * @brief PartLine::itemChange
144 * @param change
145 * @param value
146 * @return
147 */
itemChange(QGraphicsItem::GraphicsItemChange change,const QVariant & value)148 QVariant PartLine::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
149 {
150 if (change == ItemSelectedHasChanged && scene())
151 {
152 if (value.toBool() == true)
153 {
154 //When item is selected, he must to be up to date whene the selection in the scene change, for display or not the handler,
155 //according to the number of selected items.
156 connect(scene(), &QGraphicsScene::selectionChanged, this, &PartLine::sceneSelectionChanged);
157
158 if (scene()->selectedItems().size() == 1)
159 addHandler();
160 }
161 else
162 {
163 disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartLine::sceneSelectionChanged);
164 removeHandler();
165 }
166 }
167 else if (change == ItemPositionHasChanged)
168 {
169 adjusteHandlerPos();
170 }
171 else if (change == ItemSceneChange)
172 {
173 if(scene())
174 disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartLine::sceneSelectionChanged);
175
176 setSelected(false); //This is item removed from scene, then we deselect this, and so, the handlers is also removed.
177 }
178
179 return QGraphicsItem::itemChange(change, value);
180 }
181
182 /**
183 * @brief PartLine::sceneEventFilter
184 * @param watched
185 * @param event
186 * @return
187 */
sceneEventFilter(QGraphicsItem * watched,QEvent * event)188 bool PartLine::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
189 {
190 //Watched must be an handler
191 if(watched->type() == QetGraphicsHandlerItem::Type)
192 {
193 QetGraphicsHandlerItem *qghi = qgraphicsitem_cast<QetGraphicsHandlerItem *>(watched);
194
195 if(m_handler_vector.contains(qghi)) //Handler must be in m_vector_index, then we can start resize
196 {
197 m_vector_index = m_handler_vector.indexOf(qghi);
198 if (m_vector_index != -1)
199 {
200 if(event->type() == QEvent::GraphicsSceneMousePress) //Click
201 {
202 handlerMousePressEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
203 return true;
204 }
205 else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move
206 {
207 handlerMouseMoveEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
208 return true;
209 }
210 else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release
211 {
212 handlerMouseReleaseEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
213 return true;
214 }
215 }
216 }
217 }
218
219 return false;
220 }
221
222 /**
223 * @brief PartLine::adjusteHandlerPos
224 * Adjust the position of the handler item
225 */
adjusteHandlerPos()226 void PartLine::adjusteHandlerPos()
227 {
228 if(m_handler_vector.isEmpty())
229 return;
230
231 QVector<QPointF> points_vector;
232 points_vector << m_line.p1() << m_line.p2();
233
234 if (m_handler_vector.size() == points_vector.size())
235 {
236 points_vector = mapToScene(points_vector);
237 for (int i = 0 ; i < points_vector.size() ; ++i)
238 m_handler_vector.at(i)->setPos(points_vector.at(i));
239 }
240 }
241
242 /**
243 * @brief PartLine::handlerMousePressEvent
244 * @param qghi
245 * @param event
246 */
handlerMousePressEvent(QetGraphicsHandlerItem * qghi,QGraphicsSceneMouseEvent * event)247 void PartLine::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
248 {
249 Q_UNUSED(qghi);
250 Q_UNUSED(event);
251
252 m_undo_command = new QPropertyUndoCommand(this, "line", QVariant(m_line));
253 m_undo_command->setText(tr("Modifier une ligne"));
254 m_undo_command->enableAnimation();
255 return;
256 }
257
258 /**
259 * @brief PartLine::handlerMouseMoveEvent
260 * @param qghi
261 * @param event
262 */
handlerMouseMoveEvent(QetGraphicsHandlerItem * qghi,QGraphicsSceneMouseEvent * event)263 void PartLine::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
264 {
265 Q_UNUSED(qghi);
266
267 QPointF new_pos = event->scenePos();
268 if (event->modifiers() != Qt::ControlModifier)
269 new_pos = elementScene()->snapToGrid(event->scenePos());
270 new_pos = mapFromScene(new_pos);
271
272 prepareGeometryChange();
273 if (m_vector_index == 0)
274 m_line.setP1(new_pos);
275 else
276 m_line.setP2(new_pos);
277
278 adjusteHandlerPos();
279 }
280
281 /**
282 * @brief PartLine::handlerMouseReleaseEvent
283 * @param qghi
284 * @param event
285 */
handlerMouseReleaseEvent(QetGraphicsHandlerItem * qghi,QGraphicsSceneMouseEvent * event)286 void PartLine::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
287 {
288 Q_UNUSED(qghi);
289 Q_UNUSED(event);
290
291 m_undo_command->setNewValue(QVariant(m_line));
292 elementScene()->undoStack().push(m_undo_command);
293 m_undo_command = nullptr;
294 m_vector_index = -1;
295 }
296
297 /**
298 * @brief PartLine::sceneSelectionChanged
299 * When the scene selection change, if there are several primitive selected, we remove the handler of this item
300 */
sceneSelectionChanged()301 void PartLine::sceneSelectionChanged()
302 {
303 if (this->isSelected() && scene()->selectedItems().size() == 1)
304 addHandler();
305 else
306 removeHandler();
307 }
308
309 /**
310 * @brief PartLine::addHandler
311 * Add handlers for this item
312 */
addHandler()313 void PartLine::addHandler()
314 {
315 if (m_handler_vector.isEmpty() && scene())
316 {
317 QVector<QPointF> points_vector;
318 points_vector << m_line.p1() << m_line.p2();
319
320 m_handler_vector = QetGraphicsHandlerItem::handlerForPoint(mapToScene(points_vector));
321
322 for(QetGraphicsHandlerItem *handler : m_handler_vector)
323 {
324 handler->setColor(Qt::blue);
325 scene()->addItem(handler);
326 handler->installSceneEventFilter(this);
327 handler->setZValue(this->zValue()+1);
328 }
329 }
330 }
331
332 /**
333 * @brief PartLine::removeHandler
334 * Remove the handlers of this item
335 */
removeHandler()336 void PartLine::removeHandler()
337 {
338 if (!m_handler_vector.isEmpty())
339 {
340 qDeleteAll(m_handler_vector);
341 m_handler_vector.clear();
342 }
343 }
344
345 /**
346 * @brief PartLine::sceneP1
347 * @return the point p1 in scene coordinate
348 */
sceneP1() const349 QPointF PartLine::sceneP1() const {
350 return(mapToScene(m_line.p1()));
351 }
352
353 /**
354 * @brief PartLine::sceneP2
355 * @return the point p2 in scen coordinate
356 */
sceneP2() const357 QPointF PartLine::sceneP2() const {
358 return(mapToScene(m_line.p2()));
359 }
360
361 /**
362 * @brief PartLine::shape
363 * @return the shape of this item
364 */
shape() const365 QPainterPath PartLine::shape() const
366 {
367 QPainterPath shape;
368
369 //We calcul path only if there is an end type
370 //Else we just draw a line
371 if (first_end || second_end)
372 shape.addPath(path());
373 else
374 {
375 shape.moveTo(m_line.p1());
376 shape.lineTo(m_line.p2());
377 }
378
379 QPainterPathStroker pps;
380 pps.setWidth(m_hovered? penWeight()+SHADOWS_HEIGHT : penWeight());
381 shape = pps.createStroke(shape);
382
383 return shape;
384 }
385
shadowShape() const386 QPainterPath PartLine::shadowShape() const
387 {
388 QPainterPath shape;
389
390 //We calcul path only if there is an end type
391 //Else we just draw a line
392 if (first_end || second_end)
393 shape.addPath(path());
394 else
395 {
396 shape.moveTo(m_line.p1());
397 shape.lineTo(m_line.p2());
398 }
399
400 QPainterPathStroker pps;
401 pps.setWidth(penWeight());
402
403 return (pps.createStroke(shape));
404 }
405
406 /**
407 * @brief PartLine::fourShapePoints
408 * @return a list with the two points that delimite the line
409 * + the four points surrounding these two points
410 */
fourShapePoints() const411 QList<QPointF> PartLine::fourShapePoints() const
412 {
413 const qreal marge = 2.0;
414
415 QPointF a = m_line.p1();
416 QPointF b = m_line.p2();
417
418 QList<QPointF> result;
419
420 //Special case, the line is defined by one point
421 if (a == b)
422 {
423 result << QPointF(a.x() - marge, a.y() - marge);
424 result << QPointF(a.x() - marge, a.y() + marge);
425 result << QPointF(a.x() + marge, a.y() + marge);
426 result << QPointF(a.x() + marge, a.y() - marge);
427 }
428 else
429 {
430 //We calcule the vector AB : (xb-xa, yb-ya)
431 QPointF v_ab = b - a;
432
433 //And the distance AB: root of the coordinates of the vector squared
434 qreal ab = sqrt(pow(v_ab.x(), 2) + pow(v_ab.y(), 2));
435
436 //Next, we define the vector u(a, b) wich is equal to the vector AB divided
437 //by is length and multiplied by the length of marge.
438 QPointF u = v_ab / ab * marge;
439
440 //We define the vector v(-b, a) wich is perpendicular to AB
441 QPointF v(-u.y(), u.x());
442 QPointF m = -u + v; // we have vector M = -u + v
443 QPointF n = -u - v; // and vector N=-u-v
444 QPointF h = a + m; // H = A + M
445 QPointF k = a + n; // K = A + N
446 QPointF i = b - n; // I = B - N
447 QPointF j = b - m; // J = B - M
448
449 result << h << i << j << k;
450 }
451 return(result);
452 }
453
454 /**
455 * @brief PartLine::firstEndCircleRect
456 * @return the rectangle bordering the entirety of the first extremity
457 */
firstEndCircleRect() const458 QRectF PartLine::firstEndCircleRect() const
459 {
460 QList<QPointF> interesting_points = fourEndPoints(m_line.p1(),
461 m_line.p2(),
462 first_length);
463
464 QRectF end_rect(
465 interesting_points[0] - QPointF(first_length, first_length),
466 QSizeF(2.0 * first_length, 2.0 * first_length)
467 );
468
469 return(end_rect);
470 }
471
472 /**
473 * @brief PartLine::secondEndCircleRect
474 * @return the rectangle bordering the entirety of the second extremity
475 */
secondEndCircleRect() const476 QRectF PartLine::secondEndCircleRect() const {
477 QList<QPointF> interesting_points = fourEndPoints(m_line.p2(),
478 m_line.p1(),
479 second_length);
480
481 QRectF end_rect(
482 interesting_points[0] - QPointF(second_length, second_length),
483 QSizeF(2.0 * second_length, 2.0 * second_length)
484 );
485
486 return(end_rect);
487 }
488
489 /**
490 * @brief PartLine::debugPaint
491 * Display several composante of the drawing
492 * -the bounding rect
493 * -special points at each extremity
494 * -the quadrature of the circle at each extremity, even if itself is an other type
495 * @param painter
496 */
debugPaint(QPainter * painter)497 void PartLine::debugPaint(QPainter *painter)
498 {
499 painter -> save();
500 painter -> setPen(Qt::gray);
501 painter -> drawRect(boundingRect());
502
503 painter -> setPen(Qt::green);
504 painter -> drawRect(firstEndCircleRect());
505 painter -> drawRect(secondEndCircleRect());
506
507 painter -> setPen(Qt::red);
508
509 foreach(QPointF pointy, fourEndPoints(m_line.p1(), m_line.p2(), first_length))
510 painter -> drawEllipse(pointy, 0.1, 0.1);
511
512 foreach(QPointF pointy, fourEndPoints(m_line.p2(), m_line.p1(), second_length))
513 painter -> drawEllipse(pointy, 0.1, 0.1);
514
515 painter -> restore();
516 }
517
518 /**
519 * @brief PartLine::boundingRect
520 * @return the bounding rect of this part
521 */
boundingRect() const522 QRectF PartLine::boundingRect() const
523 {
524 QRectF bound;
525 if (first_end || second_end)
526 bound = path().boundingRect();
527 else
528 bound = QRectF (m_line.p1(), m_line.p2());
529
530 qreal adjust = (SHADOWS_HEIGHT + penWeight()) / 2;
531 //We add 0.5 because CustomElementGraphicPart::drawShadowShape
532 //draw a shape bigger of 0.5 when pen weight is to 0.
533 if (penWeight() == 0) adjust += 0.5;
534
535 bound = bound.normalized();
536 bound.adjust(-adjust, -adjust, adjust, adjust);
537
538 return bound;
539 }
540
541 /**
542 * @brief PartLine::isUseless
543 * @return true if this part is irrelevant and does not deserve to be Retained / registered.
544 * A line is relevant when is two point is different
545 */
isUseless() const546 bool PartLine::isUseless() const {
547 return(m_line.p1() == m_line.p2());
548 }
549
550 /**
551 * @brief PartLine::sceneGeometricRect
552 * @return the minimum, margin-less rectangle this part can fit into, in scene
553 * coordinates. It is different from boundingRect() because it is not supposed
554 * to imply any margin, and it is different from shape because it is a regular
555 * rectangle, not a complex shape.
556 */
sceneGeometricRect() const557 QRectF PartLine::sceneGeometricRect() const {
558 return(QRectF(sceneP1(), sceneP2()));
559 }
560
561 /**
562 * @brief PartLine::startUserTransformation
563 * Start the user-induced transformation, provided this primitive is contained
564 * within the \a initial_selection_rect bounding rectangle.
565 * @param initial_selection_rect
566 */
startUserTransformation(const QRectF & initial_selection_rect)567 void PartLine::startUserTransformation(const QRectF &initial_selection_rect)
568 {
569 Q_UNUSED(initial_selection_rect)
570 saved_points_.clear();
571 saved_points_ << sceneP1() << sceneP2();
572 }
573
574 /**
575 * @brief PartLine::handleUserTransformation
576 * Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
577 * @param initial_selection_rect
578 * @param new_selection_rect
579 */
handleUserTransformation(const QRectF & initial_selection_rect,const QRectF & new_selection_rect)580 void PartLine::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect)
581 {
582 QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
583 prepareGeometryChange();
584 m_line = QLineF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1)));
585 }
586
587 /**
588 * @brief PartLine::fourEndPoints
589 * Return the four interesting point needed to draw the shape
590 * at extremity of line (circle, diamond, arrow, triangle)
591 * This points are in order :
592 * O : point on the line, at a distance 'length' of the extremity
593 * A : point on the line at a 'length' of 2x the extremity length
594 * B : point at a distance of length O - O is the projection of B on the line
595 * C : point at a distance of length O - O is the projection of C on the line
596 * @param end_point : The concerned extremity
597 * @param other_point : other needed point to define the line
598 * @param length : length to use between the extremity and the point O
599 * @return
600 */
fourEndPoints(const QPointF & end_point,const QPointF & other_point,const qreal & length)601 QList<QPointF> PartLine::fourEndPoints(const QPointF &end_point, const QPointF &other_point, const qreal &length)
602 {
603 //Vector and length of the line
604 QPointF line_vector = end_point - other_point;
605 qreal line_length = sqrt(pow(line_vector.x(), 2) + pow(line_vector.y(), 2));
606
607 //Unitary vector and perpendicular vector
608 QPointF u(line_vector / line_length * length);
609 QPointF v(-u.y(), u.x());
610
611 // points O, A, B, C
612 QPointF o(end_point - u);
613 QPointF a(o - u);
614 QPointF b(o + v);
615 QPointF c(o - v);
616
617 return(QList<QPointF>() << o << a << b << c);
618 }
619
line() const620 QLineF PartLine::line() const {
621 return m_line;
622 }
623
setLine(const QLineF & line)624 void PartLine::setLine(const QLineF &line)
625 {
626 if (m_line == line) return;
627 prepareGeometryChange();
628 m_line = line;
629 adjusteHandlerPos();
630 emit lineChanged();
631 }
632
setFirstEndType(const Qet::EndType & et)633 void PartLine::setFirstEndType(const Qet::EndType &et)
634 {
635 if (first_end == et) return;
636 prepareGeometryChange();
637 first_end = et;
638 emit firstEndTypeChanged();
639 }
640
setSecondEndType(const Qet::EndType & et)641 void PartLine::setSecondEndType(const Qet::EndType &et)
642 {
643 if (second_end == et) return;
644 prepareGeometryChange();
645 second_end = et;
646 emit secondEndTypeChanged();
647 }
648
setFirstEndLength(const qreal & l)649 void PartLine::setFirstEndLength(const qreal &l)
650 {
651 qreal length = qMin(qAbs(l), m_line.length());
652 if (first_length == length) return;
653 prepareGeometryChange();
654 first_length = length;
655 emit firstEndLengthChanged();
656 }
657
setSecondEndLength(const qreal & l)658 void PartLine::setSecondEndLength(const qreal &l)
659 {
660 qreal length = qMin(qAbs(l), m_line.length());
661 if (second_length == length) return;
662 prepareGeometryChange();
663 second_length = length;
664 emit secondEndLengthChanged();
665 }
666
667 /**
668 * @brief PartLine::path
669 * @return this line has a QPainterPath.
670 * It's notably use when this line have an end type (circle, triangle etc....),
671 * because return a QPainterPath with end already draw.
672 * Else if there isn't an end type get P1 and P2 of line is better (faster).
673 */
path() const674 QPainterPath PartLine::path() const
675 {
676 QPainterPath path;
677
678 QPointF point1(m_line.p1());
679 QPointF point2(m_line.p2());
680
681 qreal line_length(m_line.length());
682 qreal pen_width = penWeight();
683
684 qreal length1 = first_length;
685 qreal length2 = second_length;
686
687 //debugPaint(painter);
688
689 //Determine if we must to draw extremity
690 qreal reduced_line_length = line_length - (length1 * requiredLengthForEndType(first_end));
691 bool draw_1st_end = first_end && reduced_line_length >= 0;
692
693 if (draw_1st_end)
694 reduced_line_length -= (length2 * requiredLengthForEndType(second_end));
695 else
696 reduced_line_length = line_length - (length2 * requiredLengthForEndType(second_end));
697
698
699 //Draw the first extremity
700 QPointF start_point;
701 if (draw_1st_end)
702 {
703 QList<QPointF> four_points1(fourEndPoints(point1, point2, length1));
704
705 if (first_end == Qet::Circle)
706 {
707 path.addEllipse(QRectF(four_points1[0] - QPointF(length1, length1), QSizeF(length1 * 2.0, length1 * 2.0)));
708 start_point = four_points1[1];
709 }
710 else if (first_end == Qet::Diamond)
711 {
712 path.addPolygon(QPolygonF() << four_points1[1] << four_points1[2] << point1 << four_points1[3] << four_points1[1]);
713 start_point = four_points1[1];
714 }
715 else if (first_end == Qet::Simple)
716 {
717 path.addPolygon(QPolygonF() << four_points1[3] << point1 << four_points1[2]);
718 start_point = point1;
719
720 }
721 else if (first_end == Qet::Triangle)
722 {
723 path.addPolygon(QPolygonF() << four_points1[0] << four_points1[2] << point1 << four_points1[3] << four_points1[0]);
724 start_point = four_points1[0];
725 }
726
727 //Adjust the start point according to the pen width
728 if (pen_width && (first_end == Qet::Simple || first_end == Qet::Circle))
729 start_point = QLineF(start_point, point2).pointAt(pen_width / 2.0 / line_length);
730 }
731 else
732 {
733 start_point = point1;
734 }
735
736 //Draw the second extremity
737 QPointF stop_point;
738 bool draw_2nd_end = second_end && reduced_line_length >= 0;
739 if (draw_2nd_end)
740 {
741 QList<QPointF> four_points2(fourEndPoints(point2, point1, length2));
742
743 if (second_end == Qet::Circle)
744 {
745 path.addEllipse(QRectF(four_points2[0] - QPointF(length2, length2), QSizeF(length2 * 2.0, length2 * 2.0)));
746 stop_point = four_points2[1];
747 }
748 else if (second_end == Qet::Diamond)
749 {
750 path.addPolygon(QPolygonF() << four_points2[2] << point2 << four_points2[3] << four_points2[1] << four_points2[2]);
751 stop_point = four_points2[1];
752 }
753 else if (second_end == Qet::Simple)
754 {
755 path.addPolygon(QPolygonF() << four_points2[3] << point2 << four_points2[2]);
756 stop_point = point2;
757 }
758 else if (second_end == Qet::Triangle)
759 {/**
760 @return true si cette partie n'est pas pertinente et ne merite pas d'etre
761 conservee / enregistree.
762 Une ligne est pertinente des lors que ses deux points sont differents
763 */
764 path.addPolygon(QPolygonF() << four_points2[0] << four_points2[2] << point2 << four_points2[3] << four_points2[0]);
765 stop_point = four_points2[0];
766 }
767
768 //Adjust the end point accordint to the pen width
769 if (pen_width && (second_end == Qet::Simple || second_end == Qet::Circle))
770 stop_point = QLineF(point1, stop_point).pointAt((line_length - (pen_width / 2.0)) / line_length);
771 }
772 else
773 {
774 stop_point = point2;
775 }
776
777 path.moveTo(start_point);
778 path.lineTo(stop_point);
779
780 return path;
781 }
782