{{notification.text}}

MirGames

AXS
29.05.09 00:31
0
Вопрос № 1) И всё таки дуга...

Прорисовываю окружность так:
Код
glBegin(GL_LINE_LOOP);
                  glColor3f (0.5, 0.5, 0.5);
                  for i:= 0 to 100 do
                    begin
                      a:=2*pi*i/100;
                      glVertex2f(DR.TempArc.CPoint.X + DR.TempArc.Radius * cos(a),
                                DR.TempArc.CPoint.Y + DR.TempArc.Radius * sin(a));
                    end;
                glEnd;


DR - Информация о чертеже.
DR.TempArc - Информация о дуге которая строится в данный момент
DR.TempArc.Radius - Радиус дуги
DR.TempArc.CPoint - Координаты центра дуги (тип T2dPoint)
Код
  T2dPoint = record
    X, Y: GLfloat;
  end;


Таким образом рисуется окружность, Но не дуга...

А в DR.TempArc есть еще два свойства DR.TempArc.BPoint и DR.TempArc.EPoint (оба T2dPoint) Они содержат координаты начальной и конечной точек дуги.

На скрине видно -

Две красные точки - это DR.TempArc.BPoint и DR.TempArc.EPoint
Синяя - это DR.TempArc.СPoint
Красно-синяя (между двумя красным это где находится курсор)


Как мне изменить код отрисовки чтоб рисовалась только дуга от первой красной точки до второй?
Делов то... (для специалиста) А я геометрически вроде понимаю как это сделать а в коде реализовать не пойму как... :blush:
Отредактировано: 29.05.09 02:22
#1
29.05.09 04:35
0
1) Вычислить углы между осью Ox и направлениями из центра окружности до точек. А лучше изначально хранить углы, а не координаты. Пусть эти углы будут A1, A2.
2)
Код

                  for i:= 0 to 100 do
                    begin
                      a:=A1 + (A2-A1)*i/100;

И LINE_LOOP заменить на LINE_STRIP.
Отредактировано: 29.05.09 04:35
#2
AXS
29.05.09 18:12
0
visual
Спасибо за подсказку насчёт углов

Но теперь возникла проблема, которой не было пока дуга "была" окружностью :)
Суть на скрине:


У нас ведь дуга рисуется всегда по часовой стрелке? ( или против если немного изменить код)
Так вот, если принять что на скрине красная точка это первая точка (BPoint),
зелёная точка это вторая точка (EPoint),
а синяя точка - положение курсора

То дуга рисуется правильно(чёрная дуга) от КРАСНОЙ точки по часовой стрелке через курсор к ЗЕЛЁНОЙ точке.

Но если пользователь указал первой точкой - зелёную, второй - красную,
то дуга будет рисоваться от первой (ЗЕЛЁНОЙ), тоже по часовой стрелке ко второй (КРАСНОЙ) точке,
НО уже не через курсор, а по другую сторону (серая дуга).

Я долго кумекал и пришел к выводу, что надо определять по какую сторону от линии соединяющей красную и зелёную точки (тонкая оранжевая линия) , находится курсор и рисовать, в зависимости от этого, по часовой или против часовой стрелки.

Пришел то пришел а как реализовать ума не приложу...
Отредактировано: 29.05.09 18:13
#3
29.05.09 19:03
0
AXS смотри определи какая точка ниже
если та которая ниже первая то....
если та которая выше вторая то.....
или можно прям как ты хочешь сначала
если красная из фёст зен отрисовка начиная с красной до зелёной.
если зелёная из фёст зен отрисовка начиная с зелёной до красной.
где отрисовка начиная с ... до ... - это функция отрисовки по часовой стрелки о кудато до кудато.
Понятно?
#4
AXS
29.05.09 19:16
0
Цитата(lans @ 29.05.2009 - 11:03) [snapback]94999[/snapback]

AXS смотри определи какая точка ниже
если та которая ниже первая то....
если та которая выше вторая то.....


Вот те 3 частных случая:



И в первом и во втором первые лежат ниже, а прорисовка в разных направлениях...

А в третьем они вообще на одной высоте... :blink:

Эти и другие похожие теории я в первую очередь рассмотрел и отбросил.
#5
AXS
29.05.09 19:32
0
Есть у меня рабочая теория



Положим что O - начало координат, А - первая точка, В - вторая, С - положение курсора.

Нужно:
Вывести линию из точки А, перпендикулярно линии АВ в направлении движения часовой стрелки.
Это будет новая ось Y. Обозначим её Yn.
Тогда новая ось X будет линия AB. Обозначим Xn
А новое начало координат - это точка А

Вот самая соль - надо вычислить координаты точки С при новом положении координат.
При этом старые координаты точки С известны...


Если новая Y координата точки больше нуля, рисуем по часовой стрелке, а если меньше нуля, то против часовой стрелки

Для примера есть точка D


Всё понятно но непойму как вычислить новые координаты точки С... Спрецировать как то что ли?..
Или относительно разницы старых и новых координат точек А и В... Они то известны...
#6
29.05.09 19:53
0
а во....можно так как ты только с небольшим знанием алгебры))))ну или геометрии)))а именно векторов...1ый вектор это нормаль к АВ (твой перпендикуляр) второй вектор это к примеру ВС или АС и если скалярное произведение векторов 1 и 2 больше нуля то почасовой стрелке елсе против))))
#7
AXS
29.05.09 20:05
0
Ок. Сечас домой приду - подумаю.
#8
Dan
The One
29.05.09 21:55
0
подсказка: крос продукт векторов ;)
lans, тоже верно говорит, можно и со скалярным произверением, но это будет в 2 действия...
Отредактировано: 29.05.09 21:59
#9
29.05.09 22:10
0
Dan а как через кросс...обясни так же как я)))
#10
Dan
The One
29.05.09 23:38
0
Изображение

как на рисунке - имеем точки A, B и С нужно узнать по какую строну от AB лежит C.
(надеюсь все знают что такое крос продукт...)
если AB cross AC > 0 то C лежит так же как на рисунке иначе лежит либо на прямой AB либо на стороне точки D
(если что AB и AC это векторы, вектор AB = B - A, вектор AC = C - A).
Отредактировано: 29.05.09 23:40
#11
AXS
29.05.09 23:45
0
cross - это по-русски произведение векторов?

PS: А вообще занимательная задачка для разминки мозгов... :)
#12
30.05.09 00:38
0
cross product с английского на русский переводится как векторное произведение
cross перекрещивание, крест
#13
Dan
The One
30.05.09 00:59
0
Код

function Vec2Cross(const v1, v2: TVec2): Single;
begin
  Result := v1.x * v2.y - v1.y * v2.x;
end;
#15
BobCat
30.05.09 03:07
0
Ммм... сколько сложностей... А не проще просто нарисовать 2 дуги AC и BC? Рисовать, соответственно, дуги в ту сторону, которая меньше (рисунок слева). Будет, конечно, один случай-исключение (рисунок справа), который устраняется просто проверкой того, что дуги направлены в разные стороны, и изменением направления одной из дуг в случае необходимости (в таком случае возможны 2 варианта - из них выбирается тот, при котором сумма длин дуг меньше 360 градусов (в другом случае сумма длин дуг будет больше 360 градусов)).
Отредактировано: 30.05.09 03:19
#16
30.05.09 04:59
0
Предлагаю такое решение.

Вычисляем углы всех трех точек: A, B, C: Single.

Далее, если C лежит между числами A и B, то рисуем дугу от min(A, B ) до max(A, B ), иначе от max(A, B ) до min(A, B ).
Отредактировано: 30.05.09 04:59
#17
30.05.09 05:01
0
AXS
ага, это векторное произведение, оно почти у всех самописное )
#18
AXS
30.05.09 14:28
0
Короче, братцы... Я вроде не нуб. Просмотрел весь код раза 4, ошибок нет, но не работает....

Уже задолбался :help:

Вообще подозрения на вот этот кусок:
Код
  CalculateAngles;
  glBegin(GL_LINE_STRIP);
    for i:= 0 to 100 do
      begin
        if DR.TempArc.HourHand then
          a:=DR.TempArc.BAngle+(DR.TempArc.EAngle-DR.TempArc.BAngle)/100*i
        else
          a:=DR.TempArc.BAngle-(DR.TempArc.EAngle-DR.TempArc.BAngle)/100*i;

        glColor3f (i/100, 0.5, 0.5);
        glVertex2f(DR.TempArc.CPoint.X+DR.TempArc.Radius*cos(a),
                                DR.TempArc.CPoint.Y+DR.TempArc.Radius*sin(a));
      end;
    glEnd;


CalculateAngles - вычисление начального и конечного углов и попутно высчитывается в какую сторону рисовать:
Код
procedure TMainForm.CalculateAngles;
var
  ProtK, PrilK: Single;
  B, E, C: T2dPoint;
begin
  B:= DR.TempArc.BPoint;
  E:= DR.TempArc.EPoint;
  C:= DR.TempArc.CPoint;
{*******************************************************************}
  if B.X > C.X then
    begin  // Точка лежит ПРАВЕЕ центра
      PrilK:=B.X - C.X;
      if B.Y > C.Y then
        begin  // Точка лежит ВЫШЕ центра
          ProtK:=B.Y - C.Y;
          DR.TempArc.BAngle:=pi - ArcTan2(ProtK, PrilK);
        end
      else
        begin   // Точка лежит НИЖЕ центра
          ProtK:=C.Y - B.Y;
          DR.TempArc.BAngle:=pi + ArcTan2(ProtK, PrilK);
        end
    end
  else
    begin  // Точка лежит ЛЕВЕЕ центра
      PrilK:=C.X - B.X;
      if B.Y > C.Y then
        begin   // Точка лежит ВЫШЕ центра
          ProtK:=B.Y - C.Y;
          DR.TempArc.BAngle:=ArcTan2(ProtK, PrilK);
        end
      else
        begin   // Точка лежит НИЖЕ центра
          ProtK:=C.Y - B.Y;
          DR.TempArc.BAngle:=2*pi - ArcTan2(ProtK, PrilK);
        end
    end;
{*******************************************************************}
  if E.X > C.X then
    begin  // Точка лежит ПРАВЕЕ центра
      PrilK:=E.X - C.X;
      if E.Y > C.Y then
        begin  // Точка лежит ВЫШЕ центра
          ProtK:=E.Y - C.Y;
          DR.TempArc.EAngle:=pi - ArcTan2(ProtK, PrilK);
        end
      else
        begin   // Точка лежит НИЖЕ центра
          ProtK:=C.Y - E.Y;
          DR.TempArc.EAngle:=pi + ArcTan2(ProtK, PrilK);
        end
    end
  else
    begin  // Точка лежит ЛЕВЕЕ центра
      PrilK:=C.X - E.X;
      if E.Y > C.Y then
        begin   // Точка лежит ВЫШЕ центра
          ProtK:=E.Y - C.Y;
          DR.TempArc.EAngle:=ArcTan2(ProtK, PrilK);
        end
      else
        begin   // Точка лежит НИЖЕ центра
          ProtK:=C.Y - E.Y;
          DR.TempArc.EAngle:=2*pi - ArcTan2(ProtK, PrilK);
        end
    end;
{*******************************************************************}
  DR.TempArc.HourHand:= GetTrend(B, E, MPos);

  SB.Panels[0].Text:='BAngle = '+FloatToStrF(DR.TempArc.BAngle*57.3, ffNumber, 6, 2)+
                     '   EAngle = '+FloatToStrF(DR.TempArc.EAngle*57.3, ffNumber, 6, 2);
end;

function TMainForm.GetTrend(a, b, c: T2dPoint): Boolean;
var
  AB, AC: T2dPoint;
  CROSS: GLfloat;
begin
  AB.X:= b.X - a.X;
  AB.Y:= b.Y - a.Y;

  AC.X:= c.X - a.X;
  AC.Y:= c.Y - a.Y;

  CROSS := AB.X * AC.Y - AB.Y * AC.X;

  Result:= CROSS > 0;
end;

#19
AXS
31.05.09 01:38
0
Всё получилось!
Завтра отпишу в чём была проблема.

profiledraft.zip
#{{post.Index}}
{{post.Author.Login}}
{{post.CreatedDate | date:'dd.MM.yy HH:mm'}}
{{post.VotesRating}}
Отредактировано: {{post.UpdatedDate | date:'dd.MM.yy HH:mm'}}