Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: supertux от Декабрь 21, 2015, 11:08



Название: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 21, 2015, 11:08
Имеется система координат в миллиметрах. В ней расположена дуга.
Что известно:
X,Y точки начала дуги
X,Y точки конца дуги
X,Y центра дуги (или точка радиуса, как  правильно назвать)
Нужно узнать размеры прямоугольника (ширина, выоста), в который эта дуга впишется.

(http://s016.radikal.ru/i335/1512/05/abeafc5232ca.jpg)

Хорда может быть не горизонтальна.

Не подкинете формулу какую-нибудь? Мне эти данные нужны для того чтобы отрисовывать дуги в QGraphicsScene через drawArc(). Или может найдется более рациональное решение данной задачи? Перерыл кучу ресурсов, англоязычных в том числе, нормального решения не нашел, все советуют использовать drawArc.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: popper от Декабрь 21, 2015, 12:03
Метод drawArc рисует дугу эллипса, вписанного в заданный прямоугольник.
Поэтому задачу можно  переформулировать так: найти уравнение эллипса по трем точкам.
Но здесь нужно уточнить, что собой представляет третья точка (центр дуги).
Вот похожее обсуждение проблемы:
http://www.gamedev.ru/code/forum/?id=33683


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 21, 2015, 12:17
Центр дуги имеется ввиду центр окружности (куда ставится игла циркуля, когда чертим дугу).

(http://i068.radikal.ru/1512/84/470ca733ebb4.jpg)


Название: Re: Размеры прямоугольника в который вписан&#
Отправлено: ibnz от Декабрь 21, 2015, 12:30
    1. Смещаем центр кривизны в начало координат.
    2. Проверяем максимумы, минимумы абсцисс точек.
    3. Если ординаты точек имеют разный знак, то в проверке участвует так же радиус с соотв знаком.
    4. Повторяем аналогично для ординат.
    5. Получаем прямоугольник { (xmin, ymax), (xmax, ymax), (xmax, ymin), (xmin, ymin)}
    6. Компенсируем смещение из 1 пункта[/li]


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: __Heaven__ от Декабрь 21, 2015, 12:36
Опишите прямоугольником всю окружность - радиус вам известен.
Отрубите всё лишнее ориентируясь на 2 точки.
Только данных всё равно мало. Нужно ещё задать направление построения дуги, я могу 2 точки соединить 2 разными способами.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 21, 2015, 12:45
Радиус мне не известен. Только координаты 3х точек.
Вот блин, забрёл я в непонятный для себя математический лес (в школе надо было учить).


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: popper от Декабрь 21, 2015, 12:49
r = sqrt( (x3-x1)*(x3-x1) + (y3-y1)*(y3-y1) )


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: __Heaven__ от Декабрь 21, 2015, 12:51
Радиус мне не известен
Вам даже координаты квадрантов (пиков) дуги известны


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 21, 2015, 13:09
Если я все правильно понял, то радиус дуги в моем случае вычисляется так?

Код:
        x3 = 20
        x1 = 10
        y3 = 15
        y1 = 25
        r = sqrt((x3-x1) * (x3-x1) + (y3-y1) * (y3-y1))
        print(r)

>>> 14.142135623730951




Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: __Heaven__ от Декабрь 21, 2015, 13:18
Тут (http://www.fxyz.ru/%D1%84%D0%BE%D1%80%D0%BC%D1%83%D0%BB%D1%8B_%D0%BF%D0%BE_%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B5/%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%B3%D0%B5%D0%BE%D0%BC%D0%B5%D1%82%D1%80%D0%B8%D1%8F/%D0%BD%D0%B0_%D0%BF%D0%BB%D0%BE%D1%81%D0%BA%D0%BE%D1%81%D1%82%D0%B8/%D1%82%D0%BE%D1%87%D0%BA%D0%B8_%D0%B8_%D0%BF%D1%80%D1%8F%D0%BC%D1%8B%D0%B5_%D0%B2_%D0%BF%D1%80%D1%8F%D0%BC%D0%BE%D1%83%D0%B3%D0%BE%D0%BB%D1%8C%D0%BD%D0%BE%D0%B9_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B5_%D0%BA%D0%BE%D0%BE%D1%80%D0%B4%D0%B8%D0%BD%D0%B0%D1%82/%D1%80%D0%B0%D1%81%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D0%B5_%D0%BC%D0%B5%D0%B6%D0%B4%D1%83_%D0%B4%D0%B2%D1%83%D0%BC%D1%8F_%D1%82%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8/) можете проверить


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: popper от Декабрь 21, 2015, 13:19
если точки р1 и р2 лежат на окружности с центром в точке р3, то расстояние между р1 и р3 должно быть равно расстоянию между р2 и р3. Что программа должна делать, если это не так?


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 21, 2015, 13:45
Чтобы было понятнее чего я пытаюсь добиться, изложу по подробнее.
В общем есть G-код для ЧПУ Mach3:

Код:
M21
G01X6.31Y5.773
G03 X20.53 Y19.836 I13.42 J12.805  <--- это
G02 I57.041 J55.944
G03 X13.459 Y19.876 I16.975 J16.321
M20

Моя задача, вывести траекторию движения, которую проходит инструмент, вырезая деталь по данному коду.

(http://s018.radikal.ru/i516/1512/1f/30bcd3dbf8ea.jpg)

(http://s017.radikal.ru/i438/1512/97/65351abe436d.jpg)



Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: __Heaven__ от Декабрь 21, 2015, 14:34
всё равно вопрос остаётся актуален
если точки р1 и р2 лежат на окружности с центром в точке р3, то расстояние между р1 и р3 должно быть равно расстоянию между р2 и р3. Что программа должна делать, если это не так?


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 21, 2015, 15:28
если точки р1 и р2 лежат на окружности с центром в точке р3, то расстояние между р1 и р3 должно быть равно расстоянию между р2 и р3. Что программа должна делать, если это не так?

Если это не так, то Exception. Но такого быть по сути не может, т. к. в G коде всегда идет центр дуги (при таком виде интерполяции). И расстояния от p1/p2 до p3 одинаковые.

(http://s020.radikal.ru/i706/1512/35/abde0d44cd4f.jpg)


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: __Heaven__ от Декабрь 21, 2015, 16:22
Точка A это текущее положение резца, так понимаю...
Можете продемонстрировать для второго примера что было бы, если я ввёл
G03 X35 Y20 I-15 J20 ?


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 21, 2015, 17:11
Точка A это текущее положение резца, так понимаю...
Можете продемонстрировать для второго примера что было бы, если я ввёл
G03 X35 Y20 I-15 J20 ?

Да, точка А известна, т. к. является текущим положением инструмента. G02 - рисуем по часовой стрелке, G03 - против.

Пример с I -15:

(http://s016.radikal.ru/i336/1512/b9/d972b56dc334.jpg)


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: __Heaven__ от Декабрь 21, 2015, 17:24
У вас CA и CB не равны по длине. Полученная кривая не является дугой окружности...
Имея 2 фиксированные точки на плоскости, вы можете соединить их дугой, центр которой будет лежать на перпендикуляре к хорде, проходящим через её середину


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: __Heaven__ от Декабрь 21, 2015, 17:26
Я хочу сказать, что нельзя задать любой центр. И в предыдущем примере задав неверный центр мы не попадём из А в В.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 21, 2015, 17:35
Я хочу сказать, что нельзя задать любой центр. И в предыдущем примере задав неверный центр мы не попадём из А в В.

То что вы говорите, это безусловно верно, НО!
Я всего навсего привел пример, что будет если сделать I -15, чисто теоретически. Сам G код пишется не вручную, а генерируется в nest-программах из DXF файлов таким образом, что CA и CB будут всегда равны.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: __Heaven__ от Декабрь 21, 2015, 17:39
Ааа. Тогда другое дело.  :)
А как вы понимаете, какой вариант дуги рассматривается, по часовой или против?


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 21, 2015, 17:53
А как вы понимаете, какой вариант дуги рассматривается, по часовой или против?

Может я не совсем понял вопроса...  При плазменной резке металла, внешний контур обычно режется по часовой, а отверстия в этой детали - против, в связи с тем, что лучшее качество кромки  всегда справа по направлению режущего инструмента.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: __Heaven__ от Декабрь 21, 2015, 17:55
Ладно, это уже мелочи реализации, забудем.
Как я уже вам сказал, вам необходимо взять и нарисовать квадрат и отрезать всё лишнее.
Резать по алгоритму:
Если дуга проходит через квадрант, то сторону квадрата, на которой лежит точка не двигаем. Остальные же модифицируем. Ниже попытался выразить мысли в рисунке.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 21, 2015, 18:06
Нарисовать это где, в QGraphicscene?  Просто я не совсем представляю как оно должно реализовываться. Если возможно, покажите мне кусочек кода, так нагляднее.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: popper от Декабрь 21, 2015, 18:45
Направление отрисовки в drawArc определяется знаком параметра spanAngle. Может ли в программу  отрисовки быть передан параметр, определяющий направление вращения дополнительно к передаваемым координатам трех точек? Я имею ввиду, передать число +1 или -1 в зависимости от вида инструкции G03 или G02.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 21, 2015, 19:03
А действительно... Может ли? Я новичок в программировании графики в Qt. Только  3 дня прошло, как я взялся это писать. ;D Могу многих нюансов не знать. Может еще spanangle и startangle вычислять придется (это если я правильно понял, spanangle - централный угол). Если вычилсить радиус дуги и центральный угол, то тогда можно будет вычислить высоту/ширину прямоугольника по формуле:

H=R-R*cos(a/2)
L=2*R*sin(a/2)
a - угол
R - радиус
H,L - стороны прямоугольника

(http://s018.radikal.ru/i506/1512/1a/4143161c0bd7.jpg)


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: ibnz от Декабрь 21, 2015, 23:34
Предполагая, что оперируем с меньшей возможной дугой:

Код:
#include <QCoreApplication>
#include <cmath>
#include <QTransform>
#include <QDebug>

QRectF getArcBoundingRect(const QPointF &p1, const QPointF &p2, const QPointF &center)
{
    QTransform centerTranslate = QTransform::fromTranslate(-center.x(), -center.y());

    //в систему координат центра кривизны
    QPointF pp1 = centerTranslate.map(p1);
    QPointF pp2 = centerTranslate.map(p2);

    // можно выкинуть, если не нужна проверка на равенство радиусов
    {
        qreal radius1 = std::hypot(pp1.x(), pp1.y());
        qreal radius2 = std::hypot(pp2.x(), pp2.y());
        if (!qFuzzyCompare(radius1, radius2)) {
           qCritical() << Q_FUNC_INFO << " radius1 != radius2";
           return QRectF();
        }
    }

    qreal radius = std::hypot(pp1.x(), pp1.y());;
    QPointF topLeft = QPointF(qMin(pp1.x(), pp2.x()), qMax(pp1.y(), pp2.y()));
    QPointF bottomRight = QPointF(qMax(pp1.x(), pp2.x()), qMin(pp1.y(), pp2.y()));
    if (pp1.x() * pp2.x() < 0) {
        if(topLeft.y() > 0){
            topLeft.ry() = qMax(topLeft.y(), radius);
        }
        if(bottomRight.y() < 0){
            bottomRight.ry() = qMin(bottomRight.y(), -radius);
        }
    }
    if (pp1.y() * pp2.y() < 0) {
        if(topLeft.x() < 0){
            topLeft.rx() = qMin(topLeft.x(), -radius);
        }
        if(bottomRight.x() > 0){
            bottomRight.rx() = qMax(bottomRight.x(), radius);
        }
    }

    // в исходную систему координат
    auto defaultTransform = centerTranslate.inverted();
    topLeft = defaultTransform.map(topLeft);
    bottomRight = defaultTransform.map(bottomRight);

    return QRectF(topLeft, bottomRight);
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug() << getArcBoundingRect(QPointF(3, -5), QPointF(5, -3), QPointF(2,-2));
    return a.exec();
}





Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 22, 2015, 11:21
Перевел код на Python (т. к. пишу на нем):

Код:
from PyQt5.QtCore import *
from PyQt5.QtGui import QTransform
from math import hypot

def getArcBoundingRect(p1, p2, center):
    centerTranslate = QTransform.fromTranslate(-center.x(), -center.y())
    pp1 = QPointF(centerTranslate.map(p1))
    pp2 = QPointF(centerTranslate.map(p2))
   
#Проверка на равенство радиусов
    radius1 = hypot(pp1.x(), pp1.y())
    radius2 = hypot(pp2.x(), pp2.y())
    if not qFuzzyCompare(radius1, radius2):
        qCritical(" radius1 != radius2")
        #return QRectF()

    radius = hypot(pp1.x(), pp1.y())
    topLeft = QPointF(min(pp1.x(), pp2.x()), max(pp1.y(), pp2.y()))
    bottomRight = QPointF(max(pp1.x(), pp2.x()), min(pp1.y(), pp2.y()))
    if (pp1.x() * pp2.x() < 0):
        if (topLeft.y() > 0):
            topLeft.ry = max(topLeft.y(), radius)
        if (bottomRight.y() < 0):
            bottomRight.ry = min(bottomRight.y(), -radius)
   
    if (pp1.y() * pp2.y() < 0):
        if (topLeft.x() < 0):
            topLeft.rx = min(topLeft.x(), -radius)
        if(bottomRight.x() > 0):
            bottomRight.rx = max(bottomRight.x(), radius)
           
    #В исходную систему координат
    defaultTransform = centerTranslate.inverted()
    topLeft = defaultTransform.map(topLeft)
    bottomRight = defaultTransform.map(bottomRight)

    return QRectF(topLeft, bottomRight)

i = 20.0
j = -5.0
aX = 6.31
aY = 5.773
bX = 20.53
bY = 19.836
a = QPointF(aX, aY)
b = QPointF(bX, bY)
c = QPointF(aX + i, aY + j)

print(getArcBoundingRect(a, b, c))

Координаты aX, aY и тд. реальные. На проверке радиусов сразу выкидывает сообщение "radius1 != radius2". Может я где с кодом на косячил.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: ibnz от Декабрь 22, 2015, 11:32
В проверке радиусов hypot можно заменить на сравнение квадратов. Будет работать быстрее.
Глянь что там за радиусы получаются. Наверное допуск больший нужен.
Замени fuzzyCompare на abs(radius1 - radius2)<delta. И поиграйся с дельтой.
Или если уверен в корректности исходных данных вообще исключи проверку.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: popper от Декабрь 22, 2015, 12:10
Мне эти данные нужны для того чтобы отрисовывать дуги в QGraphicsScene через drawArc(). Или может найдется более рациональное решение данной задачи?

Если результатом должна быть дуга на QGraphicsScene, то проще всего добавить на сцену  QGraphicsPathItem, в котором задать QPainterPath с инструкцией arcTo() внутри.

В любом случае, нужно вычислять startAngle и sweepLength (аналог spanAngle).  Для упрощения кода, вычисляющего углы, можно воспользоваться функционалом QLineF::angleTo, создав две линии из точек (A;C) и (B;C).


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 22, 2015, 12:46
Изначально у меня были мысли про arcTo. Правда мне немного не понятно как оно рисует дуги.

Пример:

Код:
        path = QPainterPath()
        path.arcTo(50, 50, 150, 60, 180, 90)
        self.ui.graphicsView.scene.addPath(path)

Что получилось:

(http://i058.radikal.ru/1512/5b/50b61fbcccf5.jpg)


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: popper от Декабрь 22, 2015, 13:24
перед отрисовкой дуги нужно выполнить
Код
C++ (Qt)
QPainterPath::moveTo(pA)
, где pA - точка начала дуги.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 23, 2015, 21:00
Я делал moveTo. Но всеравно дуги выходили с линиями. Тем не менее, благодарю за советы. Теперь мне нужно некоторое время, чтобы всё это переварить. Поколдую, может с математиками пересекусь. Потом отпишусь о результатах. Считаем этот вопрос пока открытым.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 29, 2015, 09:59
В общем, вопрос актуален.  Пока мне не удалось найти углы дуги и прямоугольник.

Немного перефразирую вопрос, для ясности.

Дана дуга с начальной точкой, конечной точкой и центром.

(http://s017.radikal.ru/i406/1512/48/92a7e4f9819a.jpg)

Мои данные:

а - точка начала дуги, b - точка конца дуги, c - центр окружности.

координаты точек:

a = {'x': 6.31, 'y': 5.773}
b = {'x': 20.53, 'y': 19.836}
c = {'x': 13.42, 'y': 12.805}

Радиус вычислил по формуле: sqrt((a['x'] - c['x']) ^ 2 + (a['y'] - c['y']) ^ 2).
Радиус = 10

Дуга может располагаться как угодно, точки дуги могут располагаться в любой из четвертей. Данные чисто для примера, но верные.

Что нужно найти:

1) Начальный угол дуги (startAngle)
2) Центральный угол (spanAngle)
3) Прямоугольник в который вписана дуга
Координаты (x, y) точки начала прямоугольника (левый нижний угол?), его ширина и высота.

(http://s017.radikal.ru/i422/1512/0b/157667761132.jpg)




Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: Igors от Декабрь 29, 2015, 16:05
Отнимаете от a и b координтаты с и подставляете в ур-е эллипса

a.x * a.x / (rx * rx) + a.y * a.y / (ry * ry) = 1;
b.x * b.x / (rx * rx) + b.y * b.y / (ry * ry) = 1;

Отсюда находите rx и ry - полуоси эллипса, макс вмещающий пр-к имеет размеры (rx*2, ry*2) и центр его в точке с. А углы у Вас просто даны по чертежу

angle_a = atan2(a.y, a.x);
angle_b = atan2(b.y, b.x);


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: popper от Декабрь 29, 2015, 18:39
Одно из затруднений при расчете - это то, что положительные углы отсчитываются против часовой стрелки, а нулевой угол соответствует горизонтальной оси.

Поэтому для упрощения расчетов предлагаю вариант с использованием функционала QLineF.
Код
C++ (Qt)
QRect rect = (c.x - r, c.y - r, 2*r, 2*r);
QLineF lineAC(a, c);
QLineF lineBC(b, c);
QLineF lineOrdinateX(c, QPoinF(-c.x, c.y));
qreal startAngle = lineAC.angleTo(lineOrdinateX);
qreal spanAngle = lineAC.angleTo(lineBC);
 

Не гарантирую отсутствие ошибок - нужно проверять. Возможно, потребуется настроить знак startAngle и spanAngle.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Декабрь 31, 2015, 14:30
Подскажите. Как рисовать в qgraphicsscene используя Qpainter.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: Kurles от Январь 08, 2016, 12:54
Подскажите. Как рисовать в qgraphicsscene используя Qpainter.
Никак. Оно не отнаследовано от QPaintDevice. Но на сцене можно размещать QGraphicsItem'ы, вот на них уже можно рисовать QPainter'ом, смотри в сторону
Код
C++ (Qt)
void QGraphicsItem::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ) [pure virtual]


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Январь 08, 2016, 18:22
С этим разобрался. Создаешь класс qgraphicsitem.
По поводу прямоугольника вроде бы есть решение. Достаточно простое. Как все проверю и налажу -  поделюсь.


Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: supertux от Январь 14, 2016, 14:33
Выручайте, коллеги!  ???

Код вычисления углов дуги (startAngle, endAngle, spanAngle):

Код:

        offset = 90*16
        startangle = 16*atan2(a.y() - c.y(), a.x() - c.x())*180 / pi
        endangle = 16*atan2(b.y() - c.y(), b.x() - c.x())*180 / pi

        if startangle < 0:
            startangle -= offset
        else:
            startangle += offset
            
        if endangle < 0:
            endangle -= offset
        else:
            endangle += offset

        spanangle = abs(endangle) - abs(startangle)

        # По часовой
        if self.direction == -1:
            if spanangle > 0:
                spanangle = -spanangle

        angles = {'start': startangle, 'end': endangle, 'span': spanangle}

        print(angles['start'] / 16, angles['end'] / 16, angles['span'] / 16)

Как я уже писал выше, моя программа считывает файл с координатами, который генерируется сторонним ПО из DXF файла. В программе для генерации таких файлов 0 градусов начинается в 12ти часах.
Я пробовал добавить смещение на 90 градусов (оффсет), но что-то не выходит все дуги отрисовать правильно. Если левый нижний и верхний угол отрисовывается корректно, то правый верхний не корректно и наоборот.
Подскажите как сделать так, чтобы все дуги отрисовывало корректно. Нужен код который будет отрисовывать Любые дуги корректно... Уже долго бьюсь с этим, руки опускаются.
Прилагаю картинку.



Название: Re: Размеры прямоугольника в который вписана дуга.
Отправлено: popper от Январь 16, 2016, 20:11
приведи входные значения (a,b,c), результаты вывода print и код отрисовки дуг, которые соответствуют результату на рисунке