Построение дуги по 2 точкам и радиусу

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 24.09.2014 (Ср) 8:18

Mikle писал(а):Из замеченных багов - надпись "Нет решения!" сильно уменьшается, если точки близко.

Какой ещё баг? Это же фича. Если надпись не входит, она масштабируется — её размер подгоняется так, чтобы она входила.

Код: Выделить всё
    If bounding_vec.X >= label_border_ow Or _
       bounding_vec.Y >= label_border_oh Then
        '
        ' Рамка полностью влезет между двумя точками
        '
    Else
        '
        ' Рамка не влезет, вычисляем, насколько её нужно уменьшить...
        '
       
        Dim scaling_factor_hor As Single
        Dim scaling_factor_ver As Single
       
        If V2GetLength(bounding_vec) < PRIM_POINT_HOVER_RADIUS Then
            '
            ' Точки слились. Рисуем надпись не между точками, а над ними.
            '
            central_point.v.Y = central_point.v.Y - label_border_h * 1.1
        Else
            scaling_factor_hor = bounding_vec.X / label_border_ow
            scaling_factor_ver = bounding_vec.Y / label_border_oh
       
            scaling_factor = NumMax(scaling_factor_hor, scaling_factor_ver)
        End If

    End If
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Построение дуги по 2 точкам и радиусу

Сообщение Mikle » 24.09.2014 (Ср) 8:21

Так она же уменьшается до нечитаемости.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 24.09.2014 (Ср) 8:24

Ну и что? Кому интересно прочитать, тот растянет точки до нужной величины.

А сам порог нечитаемости вообще определяется в каждом конкретном случае DPI монитора и остротой зрения юзера. Это если уж «академически» подходить к проблеме.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Sirik
Perspicaz
Perspicaz
Аватара пользователя
 
Сообщения: 2280
Зарегистрирован: 19.02.2004 (Чт) 16:09
Откуда: Бердичев, Украина

Re: Построение дуги по 2 точкам и радиусу

Сообщение Sirik » 24.09.2014 (Ср) 9:03

Отличный пример, но заметил одну неточность или это нормально?
duga3.jpg
duga3.jpg (43.98 Кб) Просмотров: 8045

duga3.2.jpg
duga3.2.jpg (43.55 Кб) Просмотров: 8045
Состояний же любви — десять: любовный взгляд, привязанность в мыслях, рождение желания, бессонница, исхудание, отвращение к предметам восприятия, утрата стыда, безумие, потеря сознания и смерть — вот их признаки

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 24.09.2014 (Ср) 9:13

Sirik писал(а):но заметил одну неточность или это нормально?

Совершенно ненормально. Вот это действительно баг.

В функции V2GetOxAngle исправь строку:
V2GetOxAngle = IIf(v.X > 0, 0, pi / 2)
замени на
V2GetOxAngle = IIf(v.X > 0, 0, pi)
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Построение дуги по 2 точкам и радиусу

Сообщение The trick » 24.09.2014 (Ср) 9:22

Mikle, спасибо. Понял свой косяк.
Хакер, респектище! :D
UA6527P

Sirik
Perspicaz
Perspicaz
Аватара пользователя
 
Сообщения: 2280
Зарегистрирован: 19.02.2004 (Чт) 16:09
Откуда: Бердичев, Украина

Re: Построение дуги по 2 точкам и радиусу

Сообщение Sirik » 24.09.2014 (Ср) 11:42

Общими усилиями (отдельная благодарность Debugger, Кривоус Анатолий, Хакер) реализовал так:
Код: Выделить всё
    'число Пи
Private Const Pi As Double = 3.14159265358979
    'тип Точка
Private Type t_Point
    x As Single
    y As Single
    Angle As Single
    Radius As Single
End Type
    'точки
Private A As t_Point, B As t_Point, O As t_Point

    'функция рисования дуги (ClockWise = 1 -против часовой стрелки, 0 - по часовой)
Private Function CalcArc(ByRef A As t_Point, ByRef B As t_Point, ByRef O As t_Point, ClockWise As Integer) As Long
    Dim l As Single
   
        'длина отрезка
    l = Sqr((B.x - A.x) ^ 2 + (B.y - A.y) ^ 2)
       
        'проверка длины (если половина длина меньше радиуса, то выходим)
    If l / 2 > Abs(O.Radius) Then
        CalcArc = -1
        Exit Function
    End If
       
        'если радиус отрицательный
    If O.Radius < 0 Then
        O.Radius = Abs(O.Radius)
           
        If ClockWise = 1 Then
                'против часовой стрелке
            O.x = (B.x + A.x) / 2 + (A.y - B.y) * Sqr(O.Radius ^ 2 - (l / 2) ^ 2) / l
            O.y = (B.y + A.y) / 2 + (B.x - A.x) * Sqr(O.Radius ^ 2 - (l / 2) ^ 2) / l
            A.Angle = Pi - Atan2(O.y - A.y, O.x - A.x)
            If A.Angle > Pi Then A.Angle = 2 * Pi - A.Angle
            B.Angle = Atan2(O.y - B.y, O.x - B.x) - Pi
        Else
                'по часовой стрелке
            O.x = (A.x + B.x) / 2 + (B.y - A.y) * Sqr(O.Radius ^ 2 - (l / 2) ^ 2) / l
            O.y = (A.y + B.y) / 2 + (A.x - B.x) * Sqr(O.Radius ^ 2 - (l / 2) ^ 2) / l
            A.Angle = Atan2(A.y - O.y, A.x - O.x)
            B.Angle = Atan2(B.y - O.y, B.x - O.x)
            If B.Angle < 0 Then B.Angle = B.Angle + 2 * Pi
        End If
    Else
        If ClockWise = 1 Then
                'против часовой стрелке
            O.x = (A.x + B.x) / 2 + (B.y - A.y) * Sqr(O.Radius ^ 2 - (l / 2) ^ 2) / l
            O.y = (A.y + B.y) / 2 + (A.x - B.x) * Sqr(O.Radius ^ 2 - (l / 2) ^ 2) / l
            A.Angle = Pi + Atan2(O.y - A.y, O.x - A.x)
            B.Angle = Pi + Atan2(O.y - B.y, O.x - B.x)
        Else
                'по часовой стрелке
            O.x = (B.x + A.x) / 2 + (A.y - B.y) * Sqr(O.Radius ^ 2 - (l / 2) ^ 2) / l
            O.y = (B.y + A.y) / 2 + (B.x - A.x) * Sqr(O.Radius ^ 2 - (l / 2) ^ 2) / l
            A.Angle = Atan2(A.y - O.y, A.x - O.x)
            B.Angle = Atan2(B.y - O.y, B.x - O.x)
        End If
    End If
   
    A.Angle = Round(A.Angle, 6)
    B.Angle = Round(B.Angle, 6)
    O.x = Round(O.x, 6)
    O.x = Round(O.y, 6)
   
    CalcArc = 1
End Function

    'функция рисование дуги
Private Function DrawArc()
    Dim alfa As Single, stepP As Single, x As Single, y As Single
        'определяем инкримент шага
    stepP = 0.05
    If B.Angle < A.Angle Then stepP = -0.05
       
    Picture1.Circle (O.x, O.y), 2
    Picture1.Circle (A.x, A.y), 2, vbGreen
    Picture1.Circle (B.x, B.y), 2

        'цикл
    For alfa = A.Angle To B.Angle Step stepP
        x = O.Radius * Cos(alfa) + O.x
        y = O.Radius * Sin(alfa) + O.y
        Picture1.PSet (x, y), vbBlue
    Next
End Function



Еще раз всем спасибо!
Состояний же любви — десять: любовный взгляд, привязанность в мыслях, рождение желания, бессонница, исхудание, отвращение к предметам восприятия, утрата стыда, безумие, потеря сознания и смерть — вот их признаки

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 24.09.2014 (Ср) 11:47

Sirik писал(а): 'цикл
For alfa = A.Angle To B.Angle Step stepP
x = O.Radius * Cos(alfa) + O.x
y = O.Radius * Sin(alfa) + O.y
Picture1.PSet (x, y), vbBlue
Next

Эээ... зачем такой изврат? Есть ли действительно осмысленная необходимость рисовать дугу поточечно?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Построение дуги по 2 точкам и радиусу

Сообщение The trick » 24.09.2014 (Ср) 12:53

Также добавлю что пользоваться PSet вообще не рекомендуется. Этот метод вызывает SetPixelV, который для отображения пикселя переключается в режим ядра, преобразует координаты, преобразует цвет, строит временный растр, и вызывает функцию блиттинга. Также помимо всего это сам метод PSet преобразует координаты, вызывает OleTranslateColor, в результате катастрофическая потеря производительности.
Лучше уж рисовать в массиве пикселов напрямую.
UA6527P

Sirik
Perspicaz
Perspicaz
Аватара пользователя
 
Сообщения: 2280
Зарегистрирован: 19.02.2004 (Чт) 16:09
Откуда: Бердичев, Украина

Re: Построение дуги по 2 точкам и радиусу

Сообщение Sirik » 25.09.2014 (Чт) 8:09

Это просто демонстрация) PSet не будет использовать в будущем
Состояний же любви — десять: любовный взгляд, привязанность в мыслях, рождение желания, бессонница, исхудание, отвращение к предметам восприятия, утрата стыда, безумие, потеря сознания и смерть — вот их признаки

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 25.09.2014 (Чт) 8:15

Sirik, но твой код всё равно дико кривой. Идеологически. Анти-правильный с точки зрения того, как вообще всё надо разбивать по методам, как огранизовывать структуры, какие поля в них делать.

Вот посмотри как у меня сделано: во многом показывалась не правильная математика, а организация. Почему у меня есть структура VECTOR2, и при этом есть PRIMITIVE_POINT с по сути единственным полем v? Почему бы мне просто не сделать сразу только структуру POINT с x и y, без всяких промежуточных VECTOR2? Или не оставить VECTOR2, а в PRIMITIVE_ARC_2PR не сделать у StartPoint тип VECTOR2? Потому что тогда было бы неправильно. А сейчас — правильно. Попытайся хоть впитать идею.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Построение дуги по 2 точкам и радиусу

Сообщение Mikle » 25.09.2014 (Чт) 8:40

Sirik писал(а):ClockWise = 1 -против часовой стрелки, 0 - по часовой

Против часовой стрелки будет "CounterClockWise", а "ClockWise" означает ПО часовой стрелке. У тебя получается 0 - это истина, а 1 - это ложь, запутывает.
Хакер писал(а):Почему у меня есть структура VECTOR2, и при этом есть PRIMITIVE_POINT

Я в целом согласен на счёт кривой организации кода, но твой пример неудачен, в том же DirectX для координат в 2D используют Vector2, в 3D - Vector3. Какой-нибудь Point может появиться в особых случаях, например, для целочисленных координат.
Нам когда-то давно в школе говорили, что вектор - это направленный отрезок. Это, мягко говоря, неверно.

Перечитал, понял по другому. Если твой POINT, это некая аналогия вертексу, то есть может содержать ещё, к примеру, цвет и размер, то тогда применение отдельного типа оправдано. Своё вышенаписанное не исправляю.

Sirik
Perspicaz
Perspicaz
Аватара пользователя
 
Сообщения: 2280
Зарегистрирован: 19.02.2004 (Чт) 16:09
Откуда: Бердичев, Украина

Re: Построение дуги по 2 точкам и радиусу

Сообщение Sirik » 25.09.2014 (Чт) 8:50

В самой программе на VB я ничего рисовать не буду: она служить только для расчета и передачи расчетных параметров дальше. Кроме расчета дуг есть еще расчет прямых отрезков, но это пустяк по сравнению с дугами)
Не могу понять в чем ошибка организации структуры POINT? Единственное что можно из "вынуть" только параметр Радиус
Состояний же любви — десять: любовный взгляд, привязанность в мыслях, рождение желания, бессонница, исхудание, отвращение к предметам восприятия, утрата стыда, безумие, потеря сознания и смерть — вот их признаки

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 25.09.2014 (Чт) 9:27

Mikle писал(а):но твой пример неудачен, в том же DirectX для координат в 2D используют Vector2, в 3D - Vector3.

Лол. Это DirectX неудачен :) .
А мой пример удачен. А ты просто не уловил фишку/идею.

Смысл в абстрагировании от конкретики представления сущностей и создания в своём коде типобезопасной концепции, которая позволяет создать искусственные ограничения по осуществимости тех или иных семейств операций с теми или иными сущностями.

Как затравка: подумай о том, почему с С++ существуют static_cast, dynamic_cast, reinterper_cast, в чём разнциа и какие сценарии применения у каждого оператора. Это навеет тебя на правильную волну.

Потом почитай Джоэля, его статью «как заставить неправильный код выглядеть неправильно». Тоже проникнись этой идеей. Теперь я скажу, что есть кодеры — люди, которые пишут какой-то код, и у которых высшее счастье — добиться того, чтобы код заработал, а есть программисты, очень важное качество которого — это умение правильно организовать и структуру кода, и установить набор правил таких, что (внимание!) программа с неправильным кодом не скомпилируется.

Этого и приследуем. А DirectX совершенно плохой пример, почему он должен рассматриваться как образец для подражания? У него и применение-то основное — развлекательное. Вот я бы с большей охотой посмотрел на код из какого-нибудь CAD-а: AutoCAD, SolidWorks, Компас.

А DirectX... там, к примеру, в разных местах для описания координаты и угла поворота — в обоих местах будет использоваться тип Single(float) или double. Что позволяет невозбранно по ошибке и недоразумения присвоить декартову координату переменной (полю), хранящей угол. И получить бессмысленное значение.

Это криминал и пример плохого программирования. Я не понимаю людей, которые отчего-то пишут не на ассемблере, а на ЯВУ, и при этом всё равно ведут себя так, будто пишут на ассемблере.

Хорошее программирование — это когда для декартовых координат вводится и углов вводятся обособленные типы «кордината» и «угол», такие, что компилятор будет препятствовать осуществлению присвоения значения одного типа переменной другого типа. Будет препятствовать, по крайней мере до тех пор, пока программист не напишет дисклеймер в стиле:
my_angle = ДаЯЗнаюЧтоЭтоВыглядитСтранноНоПростоДайМнеУголЧисленноРавныйКоординате(something.x)
но
my_angle = something.x случайно или преднамеренно написать не удастся — будет ошибка компиляции (несовместимые типы).

Да, в VB такой подход с введением новых типов может обернуться проблемами с производительностью большой математики, но в Си оборачивание одного поля в структуру вообще ничем не грозит (сгенерируется абсолютно такой же код), а в С++ ситуация ещё лучше из-за возможности перегружать операторы.

Так что вы хороший программист не тогда, когда ваш код скомпилировался и работает, а тогда, когда благодаря вами же придуманной концепции и вами же установленным правилам ваш код не компилируется из-за случайно допущенной ошибки. Иными словами, когда у вас мощная самодисциплина, которая пропитывает и ваш код. Это спасает, потому что ошибки делают все, в томи числе и лучшие из нас, а самодисциплинированные — не все.

Вот почитай обзоры анализатора PVS-Studio: http://habrahabr.ru/company/pvs-studio/
Там есть много обзоров с проверками кода очень известных продуктов. И в каждом находится гора тупых ошибок, вызванных описками/опечатками и невнимательностью.

Например, проверка указателя на ноль (c == 0) и проверка символа по указателю на ноль (*c == 0). Пример взят из тех же обзоров PVS-Studio — куча ошибок, где вместо первой проверки написали вторую, или наоборот. Этот тот случай, когда нужно сильно бить по рукам, но ни в коем случае не за ошибку, а за создание ситуации, при которой ошибка не всплыла тут же.

Потому в хорошей программе не будет никаких if(*c == 0): достаточно ввести inline-функцию bool IsNullChar(const char pc) { return pc == 0; }, и вместо if(*c == 0) писать if(IsNullChar(*c)), и всё.

if(*c == 0) — идеологически плохо, фактически правильно, скомпилируется.
if(c == 0) — идеологически плохо, фактически неверно (забыта звёздочка), скомпилируется.
if(IsNullChar(*c)) — идеологически верно, фактически правильно, скомпилируется.
if(IsNullChar(c)) — идеологически верно, фактически неправильно, не скомпилируется.

Абсолютно та же проблема написания типобезопасного кода недавно поднималась здесь начиная с этого поста: там я настаивал на необходимости оборачивать байтовый массив в структуру UTF8_STRING, и написании кода так, чтобы функции, ожидающие на вход или отдающие на выход UTF8-строк принимали их исключительно в виде этой структуры, так, чтобы невозможно было на вход функции, ожидающей UTF8-строк, случайно подать какой-нибудь левый байтовый массив, вообще строкой не являющийся (или являющийся, но не в UTF8-представлении, а в каком-нибудь другом).
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 25.09.2014 (Чт) 10:03

Mikle писал(а):Перечитал, понял по другому. Если твой POINT, это некая аналогия вертексу, то есть может содержать ещё, к примеру, цвет и размер, то тогда применение отдельного типа оправдано. Своё вышенаписанное не исправляю.


Ты начал думать в правильном направлении, но это всего-лишь гипотетическая половинка целесообразности такого подхода.

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

Точка в пространстве и вектор — не одно и то же.
Это главный тезис. Проникнись этой идеей.

Точка в пространстве может быть описана вектором.
Но вектор может описывать не только положение точки в пространстве, а и кучу других вещей.

Думай об этом с позиции слоёв абстрагирования.

Вектор — сущность математического толка. Выше она лезет. Эта сущность не должна знать о том, как и для чего её хотят использовать. Вектор не должен знать, что он отождествляет. Вектор — он просто вектор. That's it. И операции, которые работают именно с векторами (безотносительно того, что они «репрезентируют»), у меня определены в одном модуле вместе с описанием структуры VECTOR2.

Дальше идёт следующий слой — это слой графики. И этом более верхнем слое живёт другая сущность — примитив-точка. Это в первую очередь примитив, графический. Точка. Да, пока что он описывается вектором, и больше ничего не хранит. Но это сущеность другого толка и порядка. Векторы одно, примитивы — уже другое.

И функции, которые работают с примитивом «точка» будет обязательно иметь входные параметры типа PRIMITIVE_POINT, а чисто-мематические функции — обязательно будут иметь параметры типа VECTOR2.

_______

Вот, раз уж тебе близка тема программирования игр. Не будем ограничиваться 2D-случаем.

Вектор, как я уже сказал, может собой отождествлять очень много вещей разного толка:
  • Вектор может отождествлять положение точки в пространстве.
  • Вектор может отождествлять линейную скорость движения чего-то.
  • Вектор может отождествлять угловую скорость движения чего-либо.
  • Вектор может отождествлять просто какое-нибудь направление (например луч, примая, нормаль поверхности в некоторой точки)

Все примеры — разные вещи, разноплановые, но все могут быть выражены вектором.

Так вот, если не делать, как я, то запросто можно написать что-то такое: в переменную типа Vector3 сначала будет записано значение, отождествляющее нормаль, а потом этот вектор будет скормлен функции SetPosition, и произойдёт просто бессмысленное с точки зрения здравого смысла действие.

Или вектор угловой скорости может будет случайно сложить с вектором линейной скорости. И всё это передать куда-нибудь в SetSpeed, ожидающую просто Vector3.

И компилятор не ругнётся, этот жутко неправильный код не вызовет у него никакой тревоги!
А именно в этом цель.

Другое дело, когда от абстрактно-математического Vector3 будут порождены разные дочерние взаимо-несовместимые предметно-обоснованные типы:
  • LinerSpeed,
  • RotationSpeed,
  • Position,
  • Direction

Тогда не получится случайно угловую скорость присвоить переменной, которая хранить position чего-либо.

Тогда, если нас интересует линейная скорость движения точки какого-нибудь вращающегося тела, то придётся воспользоваться функцией-переходником, которая принимает RotationSpeed, пару Posititon (центр вращения и интересующую нас точку), а возвращает LinearSpeed. Хотя по сути это будет просто прозрачная функция-обёртка, внутри которой будет вычисляться r × [p_pos–rot_pos], то есть по сути пара вызовов: V3Sub и V2CrossProduct. И, если бы речь шла про С/С++, на этапе компиляции инлайн-функция-обёртка вообще была бы отброшена, как если бы её не было, за счёт оптимизации.

Зато типобезопасность + читаемость, плюс не получится спутать не только типы, но и, например, V3DotProduct и V3CrossProduct.

И как следствие: ошибки находим не мы и нашли пользователи, а компилятор за нас. Ошибки находятся не через месяцы, а сразу не отходя от кассы.

Думай о фундаментальных типах языка как о размерностях величин в физике, а о концептуальных типах — как о смысле тех или иных значений. Да, нельзя присваивать или сравнивать величины, одна из которых в км/ч, а другая в л/м², это не имеет смысла. И тут компилятор орёт по умолчанию, если от Double пытаются отнять String.
Но бывает и такое, что две величины, например время и удельный импульс имеют одинаковую размерность: [c]. Но то, что оба в секундах, не означает, что может приравнивать одно к другому и проводить арифметику над разнородными величинами.

Без этой, возводимой в культ, типобезопасности использование ЯВУ теряет половину смысла и превращается просто в потакание программистской лени.

Надеюсь, ты понял суть.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Построение дуги по 2 точкам и радиусу

Сообщение Mikle » 25.09.2014 (Чт) 10:40

Хакер писал(а):Точка в пространстве и вектор — не одно и то же.
Это главный тезис. Проникнись этой идеей.

Я это и не утверждал. Я сначала неверно тебя понял, а потом, менее, чем через минуту, поправился, о чём и сообщил.
А в начале, я пытался донести мысль, что КООРДИНАТЫ В N-МЕРНОМ ПРОСТРАНСТВЕ И N-МЕРНЫЙ ВЕКТОР - ЭТО ОДНО И ТО ЖЕ.
И в DirectX именно так.
Я не писал про точку.
Твои рассуждения верные, но они не ко мне. Кому-то будут полезны.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Построение дуги по 2 точкам и радиусу

Сообщение Mikle » 25.09.2014 (Чт) 11:11

Да, ещё правильнее было бы сказать, что координаты являются вектором, но не наоборот.
Я понимаю твою идеологию, но я не сторонник возводить эту идеологию в абсолют. У нас не сферический в вакууме идеальный ЯП (сам VB6 позволяет те ещё вольности). А тот же Direct3D - это высокоуровневая надстройка над низкоуровневыми функциями видеодрайвера.
У меня несколько другой подход - разные "подчасти" программы имеют разный уровень абстракции. Например, та же матрица, как и вектор, может описывать физически разные вещи. Матрицу трансформации 2D текстурных координат в любом случае бессмысленно умножать на матрицу, описывающую трансформацию в 3D пространстве, но для работы с этими матрицами я не стану делать отдельную надстройку над типом Matrix. И для векторной математики тоже не стану делать надстройки для координат, для нормалей, для скоростей и т. п. Тем более, что, даже сделав такие надстройки, мы станем перед необходимостью делать огромное количество "промежуточных" надстроек - для умножений векторов типа "нормаль" на вектора типа "координата". Такое бывает нужно, все возможные надстройки станут просто немеряно огромным кодом.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 25.09.2014 (Чт) 11:23

Mikle писал(а):Да, ещё правильнее было бы сказать, что координаты являются вектором, но не наоборот.

Если Vector3 объявлен как тройка {x; y; z}, то не всегда координаты являются даже таким вектором. Потому что координаты могут быть сферическими. И не надо говорить, что три сферические координаты технически влезут в три поля структуры Vector3. Конечно влезут, но разговор-то об осуществимости.

Mikle писал(а):Тем более, что, даже сделав такие надстройки, мы станем перед необходимостью делать огромное количество "промежуточных" надстроек - для умножений векторов типа "нормаль" на вектора типа "координата". Такое бывает нужно, все возможные надстройки станут просто немеряно огромным кодом.

Их не будет огромное количество. Просто в силу комбинаторики. Если у тебя есть N типов, возможно только N*(N-1)/2 бинарных операций между ними. Это если операции коммутативны. А если некоммутативны — в два раза больше.

А в каких случаях умножение (кстати, какое?) нормали на координату имеет смысл? Я такого случая не вижу.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Построение дуги по 2 точкам и радиусу

Сообщение Mikle » 25.09.2014 (Чт) 12:50

Хакер писал(а):Потому что координаты могут быть сферическими.

Естественно, сферические координаты - это совершенно другое. Могу уточнить, что речь о декартовых координатах, думал, что это и так понятно.
Хакер писал(а):Их не будет огромное количество. Просто в силу комбинаторики. Если у тебя есть N типов, возможно только N*(N-1)/2 бинарных операций между ними

В наборе математики D3DX около 200 функций над векторами, матрицами и кватернионами. Многие из них некомутативны, плюс ещё часто имеют больше двух параметров. Кроме того, тип возвращаемого значения - тоже, фактически, имеет тот же смысл, что и тип параметра.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Построение дуги по 2 точкам и радиусу

Сообщение Mikle » 25.09.2014 (Чт) 13:03

Mikle писал(а):в каких случаях умножение (кстати, какое?) нормали на координату имеет смысл? Я такого случая не вижу.

С помощью скалярного произведения нормали на разность координат объекта и источника света можно узнать видимость источника с данной точки поверхности (без учёта самозатенения). Это так, на вскидку.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 25.09.2014 (Чт) 13:13

Mikle писал(а):С помощью скалярного произведения нормали на разность координат объекта и источника света можно узнать видимость источника с данной точки поверхности (без учёта самозатенения). Это так, на вскидку.


О, в моей концепции это перемножение двух одинковых типов: «направление» и «направление». То есть вот это твоё утверждение неправильное:
Код: Выделить всё
для умножений векторов типа "нормаль" на вектора типа [color=#FF0000]"координата"[/color].
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Построение дуги по 2 точкам и радиусу

Сообщение Mikle » 25.09.2014 (Чт) 13:52

Я ждал этот твой ответ, и даже именно слово "направление" ждал.
Только тут всё равно "физично" не получится. Мы знаем, что килограммы можно складывать и вычитать - будут килограммы, а вот вычитание координаты из координаты даёт... опа, направление! Но на самом деле может дать и координату, например можно из координаты пассажира вычесть координату вагона, получим координату пассажира относительно вагона.
А просто направление - это тоже координата, координата одного объекта в системе отсчёта второго объекта.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 25.09.2014 (Чт) 13:57

Mikle писал(а):Только тут всё равно "физично" не получится. Мы знаем, что килограммы можно складывать и вычитать - будут килограммы, а вот вычитание координаты из координаты даёт... опа, направление! Но на самом деле может дать и координату, например можно из координаты пассажира вычесть координату вагона, получим координату пассажира относительно вагона.
А просто направление - это тоже координата, координата одного объекта в системе отсчёта второго объекта.

Именно так. Поэтому нужно иметь две функции.
Одна принимает пару координат и выдаёт результат типа «направление».
Другая принимает пару координат, и выдаёт результат типа «координата».

Обе делают одинаковую арифметику, но имеют разные типы и, что немаловажно, разные названия. За счёт этого повышается читаемость кода.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Построение дуги по 2 точкам и радиусу

Сообщение Mikle » 25.09.2014 (Чт) 14:39

Хакер писал(а):За счёт этого повышается читаемость кода.

Вот именно тут есть сомнения. Решение изначальной задачи можно было описать так:
Находим вектор, соединяющий первую точку с серединой отрезка (хорды), соединяющего первую со второй точки, и его длину:
Код: Выделить всё
  v1 = v2Scale(v2Sub(DotPos2, DotPos1), 0.5)
  L = v2Len(v1)

Проверяем, что решение существует:
Код: Выделить всё
  If L > Rad Then
    ' Решения нет
  Else
    ' Решение есть
  End If

В случае, когда есть решение, находим длину отрезка, соединяющего центр окружности с центром хорды:
Код: Выделить всё
  H = Sqr(Rad * Rad - L * L)

И сам отрезок, тут возможны два варианта:
Первый вариант, центр находится слева от отрезка |Dot1 Dot2|:
Код: Выделить всё
  v2 = v2Scale(v2Norm(Vector2(-v1.y, v1.x)), H)

Второй вариант, центр находится справа от отрезка |Dot1 Dot2|:
Код: Выделить всё
  v2 = v2Scale(v2Norm(Vector2(v1.y, -v1.x)), H)

Находим центр искомой окружности:
Код: Выделить всё
  Center = v2Add(DotPos1, v2Add(v1, v2))

Добавляем к этому иллюстрацию. (не буду, их уже было много)
Согласись, как ответ на вопрос, "как построить дугу по двум точкам и радиусу", это гораздо понятнее. Твой же вариант скорее отвечает на вопрос "как надо программировать".

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 25.09.2014 (Чт) 15:40

Хакер писал(а):За счёт этого повышается читаемость кода.

Ну вот никак не могу с этим согласится...
Для повышения читаемости кода надо давать нормальные имена, а не вводить уйму типов, которые надо на каждом шагу явно приводить друг к другу.
И если не привязываться к конкретным языкам, то в последнем варианте ещё и теряется возможность использования оператора вместо функции.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 25.09.2014 (Чт) 15:41

Qwertiy писал(а):И если не привязываться к конкретным языкам, то в последнем варианте ещё и теряется возможность использования оператора вместо функции.

Наверое наоборот? Если «привязываться к VB6»?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 25.09.2014 (Чт) 15:50

Хакер писал(а):Наверое наоборот? Если «привязываться к VB6»?

Не понял, что ты имеешь в виду под "наоборот", так что просто поясню свою мысль.
В VB6 и некоторых других языках (Джаве, например), перегрузки операторов вообще нет. Для них просто молчим, т. к. там только один способ.
Там где перегрузка операторов есть, мы можем ею воспользоваться, что удобно. Но в последнем твоём примере
Хакер писал(а):Обе делают одинаковую арифметику, но имеют разные типы и, что немаловажно, разные названия.
так что мы теряем возможность применить для такого действия оператор, поскольку перегрузка на основе возвращаемого значения невозможна (ну, может где-то она и возможна, но во всех языках, на которых я умею программировать - нет; r тому же, это не может не вызвать проблем при дальнейшем использовании, если там будет ещё охапка вариантов). Если попытаться сделать одну из функций оператором, то это получается логически неестественно, поскольку они равноправны, а выбором функции для оператора мы как бы говорим, что она приоритетна.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Построение дуги по 2 точкам и радиусу

Сообщение Хакер » 26.09.2014 (Пт) 2:57

А для векторного умножения ты и так не можешь воспользоваться перегрузкой, потому что оператор один (*), а вида умножения — два.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Построение дуги по 2 точкам и радиусу

Сообщение Mikle » 26.09.2014 (Пт) 8:12

Хакер писал(а):оператор один (*), а вида умножения — два

Меня всегда удивляло, когда язык ограничивает синтаксис новых операторов уже имеющимися, я бы вообще * для векторного умножение не использовал, а использовал что-то типа Dp3 и Cross.

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 26.09.2014 (Пт) 9:20

Хакер писал(а):А для векторного умножения ты и так не можешь воспользоваться перегрузкой

Ну я бы как раз для векторного им и воспользовался бы. А для скалярного - функцией.

UPDATE: А, понял. Ты имел в виду умножение векторов, а не векторное произведение.

Пред.

Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 55

    TopList  
cron