Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Работа для программиста > Фриланс
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 14.12.2018, 18:10   #1
Mirage_2142
Новичок
Джуниор
 
Регистрация: 14.12.2018
Сообщений: 0
По умолчанию [Delphi] Кривые Безье в пространстве

Здравствуйте.

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

С успехом использую CMS сплайны для получения кривой на плоскости из примера на сайте
http://alex-black.ru/article.php?content=109

Дополнил пример функциями FlattenPath и LineDDA для получения координат построенной кривой и все работает. Пишу на Delphi 7.

Вот только кривые строятся на плоскости для Х,У и используют функцию GDI PolyBezier
А мне нужно построить кривую заданную тремя координатам X,Y,Z, т.к. схват манипулятора меняет высоту при движении (координата Z).

Есть функция построения поверхности Безье в OpenGL, но мне не нужна поверхность , мне нужна только сглаженная кривая.

Готов рассмотреть возможность решения данной задачи за плату.
Буду благодарен за любую помощь.

Входные данные, например, такие (точки x,y,z кривой):
386;180;112
550;635;260
550;595;260
550;555;260
550;515;260
550;475;260
550;435;260
550;395;260
550;355;260
550;315;260
550;275;260
550;235;260
550;195;260
480;100;450
200;-500;400
100;-500;400
400;0;15
Mirage_2142 вне форума Ответить с цитированием
Старый 14.12.2018, 18:25   #2
Mirage_2142
Новичок
Джуниор
 
Регистрация: 14.12.2018
Сообщений: 0
По умолчанию

Вот модуль, который я написал для построения кривой по CMS сплайнам.
На вход функция BezierTrajDraw получает StringList в формате X;Y точек между которыми должна построиться кривая
Возвращает StringList в формате X;Y точек сглаженной кривой
Если передан Canvas, то на нем строиться сама кривая

Но как я написал в пред. посте мне нужна функция получающая X,Y,Z
и возвращающая сглаженную кривую с координатами X,Y,Z

Код:
unit BezierTraj;

interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls,math;

  procedure BezierTrajDraw(StrList_Points:TStringList; StrList_Traj:TStringList; Canvas:TCanvas = nil);

implementation

type
  PGPPointF = ^TGPPointF;
  TGPPointF = packed record
    X : Single;
    Y : Single;
  end;
  TGPoint = TGPPointF;
  ArrayOfPoint = array of TGPoint;

var
  Curve_Strl:TStringList;
  bPaint:boolean;

procedure LineDrawFunc(X,Y:Integer;Canvas:TCanvas);stdcall;
begin
  // рисуем траекторию на Canvas
  if bPaint then
  begin
    Canvas.Pen.Style:=psSolid;
    Canvas.Pen.Width:=1;
    Canvas.Pen.Color:=clRed;

    Canvas.MoveTo(X,Y);
    Canvas.LineTo(X+1,Y+1)
  end;

  Curve_Strl.Add(inttostr(X)+';'+inttostr(Y));
end;

// Возвращает список кривых Безье, аппроксимирующих переданный массив точек
function toCMSlines(Points:array of TGPoint; closed:boolean=true; asClosed:boolean=true):ArrayOfPoint;
var C, i, CE, N1, N2, k:integer;
    P1, P2, P0, C0, B0, P0C:TGPoint;
begin
   k := 0;
   C := High(Points) - Low(Points) + 1;
   CE := C;
   if not closed then dec(CE);
   SetLength(result, CE * 3+1);

   for i := 0 to C-1 do begin
      P0 := Points[i];

      // Получаем предыдущую и следующую точки
      N1 := i-1;
      if N1 < 0 then
         if closed or asClosed then N1 := C-1 else N1 := i;

      N2 := i+1;
      if N2 > C-1 then
         if closed or asClosed then N2 := 0 else N2 := i;

      P1 := Points[N1];
      P2 := Points[N2];

      // Половина вектора (P1,P2)
      P2.X := (P2.X - P1.X)/2;
      P2.Y := (P2.Y - P1.Y)/2;

      // Опорные точки двух соседних кривых Безье
      C0.X := P0.X - P2.X/3;
      C0.Y := P0.Y - P2.Y/3;
      B0.X := P0.X + P2.X/3;
      B0.Y := P0.Y + P2.Y/3;

      if i = 0
      then P0C := C0
      else begin
         result[k] := C0; inc(k);
      end;
      result[k] := P0; inc(k);
      if (i < C-1) or closed then begin
         result[k] := B0; inc(k);
      end;
   end;
   if closed then begin
      result[k] := P0C; inc(k);
      result[k] := Points[0];
   end;
end;


procedure BezierTrajDraw(StrList_Points:TStringList;StrList_Traj:TStringList;Canvas:TCanvas = nil);
var C,i:integer;

    Points_B : array of TGPoint;
    APoints : ArrayOfPoint;
    P:TGPoint;

    Points_A:array of TPoint;

     Size:Integer;
     PtBuf:array of TPoint;
     TpBuf:array of Byte;
     L:Extended;

     DrawImage:TImage;

     pos_ind:integer;

     TMP_Canvas:TCanvas;
begin

   SetLength(Points_B,StrList_Points.Count);
   for i:=0 to StrList_Points.Count-1 do
   begin
     pos_ind:=pos(';',StrList_Points[i]);

     TGPoint(Points_B[i]).X:=strtoint(copy(StrList_Points[i],1,pos_ind-1));
     TGPoint(Points_B[i]).Y:=strtoint(copy(StrList_Points[i],pos_ind+1,length(StrList_Points[i])));
   end;


   APoints := toCMSlines(Points_B, false, false);


   C := High(APoints) - Low(APoints) + 1 ;
   setlength(Points_A, C);

   for i := 0 to C-1 do
   begin
     P:=APoints[i];
     Points_A[i].X:= Round(P.X);
     Points_A[i].Y:= Round(P.Y);
   end;


   // =========== получение разбивки кривой на отрезки ==================
   Curve_Strl:=StrList_Traj;

   DrawImage:=nil;

   if Canvas<>nil then
   begin
     TMP_Canvas:=Canvas;
     bPaint:=true;
   end
   else
   begin
     DrawImage:=TImage.Create(nil);
     DrawImage.Parent:=nil;
     TMP_Canvas:=DrawImage.Canvas;

     bPaint:=false;
   end;


   BeginPath(TMP_Canvas.Handle);
   TMP_Canvas.PolyBezier(Points_A);
   EndPath(TMP_Canvas.Handle);
   FlattenPath(TMP_Canvas.Handle);
   Size:=GetPath(TMP_Canvas.Handle,I,I,0);
   SetLength(PtBuf,Size);
   SetLength(TpBuf,Size);
   GetPath(TMP_Canvas.Handle,PtBuf[0],TpBuf[0],Size);


   for I:=1 to Size-1 do
   begin
     L:=Sqrt(Sqr(PtBuf[I-1].X-PtBuf[I].X)+Sqr(PtBuf[I-1].Y-PtBuf[I].Y));
     if L>0 then
       LineDDA(PtBuf[I-1].X,PtBuf[I-1].Y,PtBuf[I].X,PtBuf[I].Y,@LineDrawFunc,Integer(TMP_Canvas))
   end;

   if Canvas=nil then
     DrawImage.Free;

end;

end.
Mirage_2142 вне форума Ответить с цитированием
Старый 15.12.2018, 00:10   #3
Black Fregat
Программист
Участник клуба
 
Аватар для Black Fregat
 
Регистрация: 23.06.2009
Сообщений: 1,772
По умолчанию

Если актуально, напишите подробнее на black.fregat@gmail.com - пообщаемся
Black Fregat вне форума Ответить с цитированием
Старый 15.12.2018, 15:35   #4
Mirage_2142
Новичок
Джуниор
 
Регистрация: 14.12.2018
Сообщений: 0
По умолчанию

Задача решена и вопрос снимается.
Mirage_2142 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[OpenGl Delphi] Чайник из поверхности безье neomax38 Мультимедиа в Delphi 20 15.05.2012 16:19
delphi поверхность Безье un_known Мультимедиа в Delphi 8 27.03.2012 07:18
Кривая Безье. Muaxaxa Общие вопросы Delphi 2 28.11.2011 01:03
Кривая Безье. Muaxaxa Помощь студентам 2 28.11.2011 00:49
на чем в Delphi можно построить простой график от двух перменных в трехмерном пространстве Rekky Общие вопросы Delphi 17 05.05.2010 18:04