valentina/widgets/vcontrolpointspline.cpp
2013-08-05 11:37:56 +03:00

120 lines
4.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "vcontrolpointspline.h"
#include <QPen>
#include <QBrush>
#include <QGraphicsScene>
#include <QDebug>
VControlPointSpline::VControlPointSpline(const QPointF &controlPoint, const QPointF &splinePoint,
QGraphicsItem *parent):QGraphicsEllipseItem(parent){
radius = 1.5*PrintDPI/25.4;
//create circle
QRectF rec = QRectF(0, 0, radius*2, radius*2);
rec.translate(-rec.center().x(), -rec.center().y());
this->setRect(rec);
this->setPen(QPen(Qt::black, widthHairLine));
this->setBrush(QBrush(Qt::NoBrush));
this->setFlag(QGraphicsItem::ItemIsSelectable, true);
this->setFlag(QGraphicsItem::ItemIsMovable, true);
this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
this->setAcceptHoverEvents(true);
this->setPos(controlPoint);
//Лінія, що з'єднує дві точки
QPointF p1, p2;
LineIntersectCircle(QPointF(), radius, QLineF( QPointF(), splinePoint-controlPoint), p1, p2);
controlLine = new QGraphicsLineItem(QLineF(splinePoint-controlPoint, p1), this);
controlLine->setPen(QPen(Qt::red, widthHairLine));
controlLine->setFlag(QGraphicsItem::ItemStacksBehindParent, true);
}
void VControlPointSpline::hoverMoveEvent(QGraphicsSceneHoverEvent *event){
Q_UNUSED(event);
this->setPen(QPen(Qt::black, widthMainLine));
}
void VControlPointSpline::hoverLeaveEvent(QGraphicsSceneHoverEvent *event){
Q_UNUSED(event);
this->setPen(QPen(Qt::black, widthHairLine));
}
QVariant VControlPointSpline::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value){
if (change == ItemPositionChange && scene()) {
// value - это новое положение.
QPointF newPos = value.toPointF();
qDebug()<<this->rect();
QRectF rect = scene()->sceneRect();
if (!rect.contains(newPos)) {
// Сохраняем элемент внутри прямоугольника сцены.
newPos.setX(qMin(rect.right(), qMax(newPos.x(), rect.left())));
newPos.setY(qMin(rect.bottom(), qMax(newPos.y(), rect.top())));
emit ControlPointChangePosition(newPos);
return newPos;
}
emit ControlPointChangePosition(newPos);
}
return QGraphicsItem::itemChange(change, value);
}
qint32 VControlPointSpline::LineIntersectCircle(QPointF center, qreal radius, QLineF line, QPointF &p1,
QPointF &p2) const{
const qreal eps = 1e-8;
//коефіцієнти для рівняння відрізку
qreal a = line.p2().y() - line.p1().y();
qreal b = line.p1().x() - line.p2().x();
// В даному випадку не використовується.
//qreal c = - a * line.p1().x() - b * line.p1().y();
// проекция центра окружности на прямую
QPointF p = ClosestPoint (line, center);
// сколько всего решений?
qint32 flag = 0;
qreal d = QLineF (center, p).length();
if (qAbs (d - radius) <= eps){
flag = 1;
} else {
if (radius > d){
flag = 2;
} else {
return 0;
}
}
// находим расстояние от проекции до точек пересечения
qreal k = sqrt (radius * radius - d * d);
qreal t = QLineF (QPointF (0, 0), QPointF (b, - a)).length();
// добавляем к проекции векторы направленные к точкам пеерсечения
p1 = addVector (p, QPointF (0, 0), QPointF (- b, a), k / t);
p2 = addVector (p, QPointF (0, 0), QPointF (b, - a), k / t);
return flag;
}
QPointF VControlPointSpline::ClosestPoint(QLineF line, QPointF p) const{
QLineF lineP2pointFrom = QLineF(line.p2(), p);
qreal angle = 180-line.angleTo(lineP2pointFrom)-90;
QLineF pointFromlineP2 = QLineF(p, line.p2());
pointFromlineP2.setAngle(pointFromlineP2.angle()+angle);
QPointF point;
QLineF::IntersectType type = pointFromlineP2.intersect(line,&point);
if ( type == QLineF::BoundedIntersection ){
return point;
} else{
if ( type == QLineF::NoIntersection || type == QLineF::UnboundedIntersection ){
Q_ASSERT_X(type != QLineF::BoundedIntersection, Q_FUNC_INFO, "Немає точки перетину.");
return point;
}
}
return point;
}
QPointF VControlPointSpline::addVector(QPointF p, QPointF p1, QPointF p2, qreal k) const{
return QPointF (p.x() + (p2.x() - p1.x()) * k, p.y() + (p2.y() - p1.y()) * k);
}
void VControlPointSpline::RefreshLine(const QPointF &controlPoint, const QPointF &splinePoint){
// QRectF rec = QRectF(0, 0, radius*2, radius*2);
// rec.translate(0-rec.center().x(), 0-rec.center().y());
// this->setRect(rec);
QPointF p1, p2;
LineIntersectCircle(QPointF(), radius, QLineF( QPointF(), splinePoint-controlPoint), p1, p2);
controlLine->setLine(QLineF(splinePoint-controlPoint, p1));
}