САПР на Lazarus

Планы, идеология, архитектура и т.п.

Модератор: Модераторы

Re: САПР на Lazarus

Сообщение Alex2013 » 10.09.2019 23:42:28

Смотрится весьма неплохо, про функциональность сказать что-то не проверив на практике сложно
(но на интуитивном уровне кажется "так и должно быть " ну разве что чуть избыточное информирование в дереве хотя думаю это скорее всего настраивается (Я бы часть инфы вообще выдав в форме "хинт-образной " таблички но разумеется "хозяин барин"... ) )
Зы
Кстати не думешь делать в Z-Cad режим презентации? Не то что-бы что-то вроде "полного рендаринга " с анимацией (кстати в простершем варианте сделать и её так уж сложно ), а просто немного более проработанную и обработанную картинку с "нескучным фоном "... В качестве "буносной функции" можно добавить генерацию стереопар и аниглифа (Просто как двери но реально "Внушает" 8) )

ИзображениеИзображение
(Та что сделал я пока липовая(но и она при просмотре в ВиАр помогает ), а вот та что СНАРУЖИ ("планетарий" со звездами ) вполне реальная )
Alex2013
долгожитель
 
Сообщения: 3049
Зарегистрирован: 03.04.2013 11:59:44

Re: САПР на Lazarus

Сообщение zub » 11.09.2019 10:14:13

>>а просто немного более проработанную и обработанную картинку с "нескучным фоном "
нет. в текущем положении дел - не до улучшений картинки. Ближайшее свободное время планирую потратить на сапр составляющую (есть пара идей), в движек полезу только если всплывет какаянить не допускающая отлогательств бяка.
Из красивостей можно замутить полноэкранный режим. Вроде все к этому готово должно быть, только контрол отображения оторвать и растянуть на весь экран
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: САПР на Lazarus

Сообщение MylnikovDm » 02.03.2020 16:02:28

Привет, Zub!

В ветке про кривые Безье ты сказал, что в ЗКаде нет кривых Безье, поскольку некогда было разбираться с математикой.

Вот готовые функции вычисления координат точек для кривых Безье 2 и 3 порядка.
Код: Выделить всё
    interface

    type

      TDblPoint = packed record
        x, y: double;
      end;
      PDblPoint = ^TDblPoint;

    //расчёт точек для кривой Безье
    //если количество точек aStep указано равным 0, либо оно меньше количества точек в aPoints
    //то количество точек определяется из параметров массива aPoints
    //первая и последняя точка включаются в состав точек и указанное количество
    //то есть, если aStep = 5, то будет добавлено 3 точки внутри кривой, плюс первая и
    //последняя опорные точки
    procedure Bezie2Points(aP1, aP2, aP3: TPoint; var aPoints: array of TPoint; aStep: integer = 0); overload;
    procedure Bezie2Points(aP1, aP2, aP3: TDblPoint; var aPoints: array of TDblPoint; aStep: integer = 0); overload;

    procedure Bezie3Points(aP1, aP2, aP3, aP4: TPoint; var aPoints: array of TPoint; aStep: integer = 0); overload;
    procedure Bezie3Points(aP1, aP2, aP3, aP4: TDblPoint; var aPoints: array of TDblPoint; aStep: integer = 0); overload;

    implementation

    procedure Bezie3Points(aP1, aP2, aP3, aP4: TPoint; var aPoints: array of TPoint; aStep: integer = 0);
    const
      MsInt = 4;
    var
      i, SegmCount: integer;
      pl1, pl2, pl3, tp1, tp2, tp3, bp1, bp2: TPoint;
    begin
      SegmCount := Length(aPoints);
      if (aStep = 0) or (aStep > SegmCount) then begin
        aStep := SegmCount;
        if aStep < 2 then exit;
      end; // if

      aStep -= 2;
      SegmCount := aStep + 1;

      aPoints[0].X := aP1.x;
      aPoints[0].Y := aP1.Y;

      if aStep < 1 then begin
        aPoints[1].X := aP4.x;
        aPoints[1].Y := aP4.Y;
        Exit;
      end; // if
      aPoints[SegmCount].X := aP4.x;
      aPoints[SegmCount].Y := aP4.Y;

      aP1.x := aP1.x shl MsInt;
      aP1.y := aP1.y shl MsInt;
      aP2.x := aP2.x shl MsInt;
      aP2.y := aP2.y shl MsInt;
      aP3.x := aP3.x shl MsInt;
      aP3.y := aP3.y shl MsInt;
      aP4.x := aP4.x shl MsInt;
      aP4.y := aP4.y shl MsInt;

      pl1.x := aP2.x - aP1.x;
      pl1.y := aP2.y - aP1.y;

      pl2.x := aP3.x - aP2.x;
      pl2.y := aP3.y - aP2.y;

      pl3.x := aP4.x - aP3.x;
      pl3.y := aP4.y - aP3.y;

      for i := 1 to aStep do begin
        tp1.x := aP1.x + ((pl1.x * i) div SegmCount);
        tp1.y := aP1.y + ((pl1.y * i) div SegmCount);
        tp2.x := aP2.x + ((pl2.x * i) div SegmCount);
        tp2.y := aP2.y + ((pl2.y * i) div SegmCount);
        tp3.x := aP3.x + ((pl3.x * i) div SegmCount);
        tp3.y := aP3.y + ((pl3.y * i) div SegmCount);

        bp1.x := tp1.x + (((tp2.x - tp1.x) * i) div SegmCount);
        bp1.y := tp1.Y + (((tp2.y - tp1.y) * i) div SegmCount);
        bp2.x := tp2.x + (((tp3.x - tp2.x) * i) div SegmCount);
        bp2.y := tp2.Y + (((tp3.y - tp2.y) * i) div SegmCount);


        aPoints[i].X := (bp1.x + (((bp2.x - bp1.x) * i) div SegmCount)) shr MsInt;
        aPoints[i].Y := (bp1.Y + (((bp2.y - bp1.y) * i) div SegmCount)) shr MsInt;
      end; // for
    end;

    procedure Bezie3Points(aP1, aP2, aP3, aP4: TDblPoint; var aPoints: array of TDblPoint; aStep: integer = 0);
    var
      i, SegmCount: integer;
      pl1, pl2, pl3, tp1, tp2, tp3, bp1, bp2: TDblPoint;
    begin
      SegmCount := Length(aPoints);
      if (aStep = 0) or (aStep > SegmCount) then begin
        aStep := SegmCount;
        if aStep < 2 then exit;
      end;

      aStep -= 2;
      SegmCount := aStep + 1;

      aPoints[0].X := aP1.x;
      aPoints[0].Y := aP1.Y;

      if aStep < 1 then begin
        aPoints[1].X := aP4.x;
        aPoints[1].Y := aP4.Y;
        Exit;
      end; // if
      aPoints[SegmCount].X := aP4.x;
      aPoints[SegmCount].Y := aP4.Y;

      pl1.x := aP2.x - aP1.x;
      pl1.y := aP2.y - aP1.y;

      pl2.x := aP3.x - aP2.x;
      pl2.y := aP3.y - aP2.y;

      pl3.x := aP4.x - aP3.x;
      pl3.y := aP4.y - aP3.y;

      for i := 1 to aStep do begin
        tp1.x := aP1.x + ((pl1.x * i) / SegmCount);
        tp1.y := aP1.y + ((pl1.y * i) / SegmCount);
        tp2.x := aP2.x + ((pl2.x * i) / SegmCount);
        tp2.y := aP2.y + ((pl2.y * i) / SegmCount);
        tp3.x := aP3.x + ((pl3.x * i) / SegmCount);
        tp3.y := aP3.y + ((pl3.y * i) / SegmCount);

        bp1.x := tp1.x + (((tp2.x - tp1.x) * i) / SegmCount);
        bp1.y := tp1.Y + (((tp2.y - tp1.y) * i) / SegmCount);
        bp2.x := tp2.x + (((tp3.x - tp2.x) * i) / SegmCount);
        bp2.y := tp2.Y + (((tp3.y - tp2.y) * i) / SegmCount);


        aPoints[i].X := bp1.x + (((bp2.x - bp1.x) * i) / SegmCount);
        aPoints[i].Y := bp1.Y + (((bp2.y - bp1.y) * i) / SegmCount);
      end; // for
    end;

    procedure Bezie2Points(aP1, aP2, aP3: TPoint; var aPoints: array of TPoint; aStep: integer = 0);
    const
      MsInt = 4;
    var
      i, SegmCount: integer;
      pl1, pl2, tp1, tp2: TPoint;
    begin
      SegmCount := Length(aPoints);
      if (aStep = 0) or (aStep > SegmCount) then begin
        aStep := SegmCount;
        if aStep < 2 then exit;
      end; // if

      aStep -= 2;
      SegmCount := aStep + 1;

      aPoints[0].X := aP1.x;
      aPoints[0].Y := aP1.Y;

      if aStep < 1 then begin
        aPoints[1].X := aP3.x;
        aPoints[1].Y := aP3.Y;
        Exit;
      end; // if
      aPoints[SegmCount].X := aP3.x;
      aPoints[SegmCount].Y := aP3.Y;

      pl1.x := (aP2.x - aP1.x) shl MsInt;
      pl1.y := (aP2.y - aP1.y) shl MsInt;

      pl2.x := (aP3.x - aP2.x) shl MsInt;
      pl2.y := (aP3.y - aP2.y) shl MsInt;

      for i := 1 to aStep do begin
        tp1.x := aP1.x + ((pl1.x * i) div SegmCount);
        tp1.y := aP1.y + ((pl1.y * i) div SegmCount);
        tp2.x := aP2.x + ((pl2.x * i) div SegmCount);
        tp2.y := aP2.y + ((pl2.y * i) div SegmCount);

        aPoints[i].X := (tp1.x + (((tp2.x - tp1.x) * i) div SegmCount)) shr MsInt;
        aPoints[i].Y := (tp1.Y + (((tp2.y - tp1.y) * i) div SegmCount)) shr MsInt;
      end; // for
    end;

    procedure Bezie2Points(aP1, aP2, aP3: TDblPoint; var aPoints: array of TDblPoint; aStep: integer = 0);
    var
      i, SegmCount: integer;
      pl1, pl2, tp1, tp2: TDblPoint;
    begin
      SegmCount := Length(aPoints);
      if (aStep = 0) or (aStep > SegmCount) then begin
        aStep := SegmCount;
        if aStep < 2 then exit;
      end;

      aStep -= 2;
      SegmCount := aStep + 1;

      aPoints[0].X := aP1.x;
      aPoints[0].Y := aP1.Y;

      if aStep < 1 then begin
        aPoints[1].X := aP3.x;
        aPoints[1].Y := aP3.Y;
        Exit;
      end; // if
      aPoints[SegmCount].X := aP3.x;
      aPoints[SegmCount].Y := aP3.Y;

      pl1.x := aP2.x - aP1.x;
      pl1.y := aP2.y - aP1.y;

      pl2.x := aP3.x - aP2.x;
      pl2.y := aP3.y - aP2.y;

      for i := 1 to aStep do begin
        tp1.x := aP1.x + ((pl1.x * i) / SegmCount);
        tp1.y := aP1.y + ((pl1.y * i) / SegmCount);
        tp2.x := aP2.x + ((pl2.x * i) / SegmCount);
        tp2.y := aP2.y + ((pl2.y * i) / SegmCount);

        aPoints[i].X := tp1.x + (((tp2.x - tp1.x) * i) / SegmCount);
        aPoints[i].Y := tp1.Y + (((tp2.y - tp1.y) * i) / SegmCount);
      end; // for
    end;

Для целочисленного варианта используется масштабирование сдвигом на 4 разряда, чтобы не терялась точность вычислений, иначе видны косяки округления при делении.
MylnikovDm
постоялец
 
Сообщения: 103
Зарегистрирован: 15.02.2007 21:26:10
Откуда: Челябинск

Re: САПР на Lazarus

Сообщение zub » 03.03.2020 01:49:48

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

Для аппроксимации я использую GLU она умеет автоматически подогнать детализации в зависимости от матриц вида.

В автокаде из криволинейных базовых dxf примитивов есть
1 - 3Dpolyline с сглаживанием квадратичное и кубическое
2 - 2Dpolyline с дуговыми сегметами
3 - spline
Собственно эти случаи мне и интересны, безье мне нужен только при чтении ttf - но там хватает сил GLU и параметрическая точка c длиной для рисования ттф мне ненужны.

как я уже говорил, в зкаде кривые в зачаточном состоянии 1 и 2 только "линейные" версии без cглаживаний, 3 только отображается и редактируется по контрольным точкам.
для полной поддержки необходимо:
1 - ЕМНИП сглаженые версии 3d полилиний являются b сплайнами, не Безье. математика для работы с б сплайнами - длина и параметр
2 - добавление дуг на "низкий" уровень движка
3 - автокадные сплайны это NURBS, соответственно. математика для работы с NURBS сплайнами - длина и параметр - тут вообще тушите свет, похоже математическое образование надо((

1,3 - с точки зрения програмирования добавить просто, с точки зрения математики: 1 - надеюсь несложно, но я не разбирался; 2 - сложно,мне не по зубам.
2 - нужна серьезная переработка движка (низкоуговнего-графического не dxf), на низком уровне пока есть только отрезки и треугольники

зы. извиняюсь, в исходной теме сообщение неувидел((
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: САПР на Lazarus

Сообщение MylnikovDm » 06.03.2020 00:00:25

Сижу второй день "курю" всяческую инфу по поводу NURBS. При этом складывается такое ощущение, что все статьи по ним специально написаны таким образом, чтобы было ни хрена не понятно, как из этих формул перейти к конкретным вычислениям для конкретной задачи. :)

Тем не менее, по ходу изучения я выяснил, что кривые Безье являются частным случаем NURBS, которые, в свою очередь, являются нерегулярными B-сплайнами (буквочки BS в слове NURBS это как раз от b-spline). То есть, кривая Безье это b-spline, у которого количество опорных точек равно степени кривой + 1. У квадратичной получаем 3 опорных точки, у кубической, соответственно, 4 точки. Ну и так далее.

Ещё немного посидев над этим делом, я понял, что тот алгоритм, который я использовал для расчёта точек кривых Безье можно модифицировать для расчёта NURBS с произвольным количеством опорных точек. Но пока это только для 2д режима. Как это прикрутить к 3д поверхностям, нужно ещё разбираться.

Да, по поводу автокада. Насколько я понял, они используют NURBS только при моделировании 3д поврехностей. При построении 2д сплайнов у них какой-то другой алгоритм, поскольку кривая проходит через сами точки, а у NURBS она проходит только в первой и последней точке, как у кривой Безье. Так что, скорее всего, это просто кубические сплайны, а не NURBS.

По поводу 2, то есть дуг в полилиниях. Ты не думал сделать средний слой, чтобы не переделывать нижний уровень движка? То есть, преобразовывать дуги и вообще любые кривые в набор отрезков, у уже потом этот набор отрезков рисовать тем движком, который есть. Нужно будет только правильно задать количество сегментов разбиения. Чем больше сегментов, тем выше точность и гладкость кривой. Автокад, как мне кажется, до сих пор так с окружностями работает.

Добавлено спустя 11 минут 17 секунд:
Для редактирования нужно уметь считать ближайшую точку на кривой до курсора мыши (в зкаде курсор это прямая из камеры в 2д курсор мыши). Параметрическую точку на кривой, ну и расчет длины кривой - чтоб можно было легко находить середину, треть, четверть и т.п.


Ближайшую точку на кривой в принципе можно вычислять по аппроксимирующей полилинии из прямых отрезков, если разбиение достаточно большое. Хотя, не совсем понятно, для чего это надо, поскольку кривая Безье обычно редактируется через управляющие точки, а не через положение самой линии. Для выделения объекта вполне достаточно будет результирующей полилинии из отрезков. А после выделения нужно отобразить управляющие точки, и перемещать уже их.

Написать функцию для нахождения произвольной точки по параметру t, где 0 <= t <= 1, вообще не проблема. Нужно только немного переделать те функции, которые есть.

Что касается нахождения середины, четверти, трети и т.п., это тоже не проблема, если решена предыдущая задача, которая возвращает координаты точки по параметру t, поскольку середина это t=0.5, четверть это t=0.25 и т.д. Тут длину в принципе вычислять не нужно. :)
MylnikovDm
постоялец
 
Сообщения: 103
Зарегистрирован: 15.02.2007 21:26:10
Откуда: Челябинск

Re: САПР на Lazarus

Сообщение zub » 06.03.2020 09:17:39

Автокад для сплайнов использует именно нурбс (2д-3д неважно, они вообще не различаются), то что сплайн проходит через точки это просто режим отображения fit \ control points, сплайн при переключении режимов не меняется, меняется принцип редактирования fit - точки на сплайне, control points - точки как в нурбс учебниках. Было бы здорово также уметь пересчитывать fit в control и обратно.
Вот описание dxf сплайна https://knowledge.autodesk.com/ru/searc ... 4-htm.html обрати основные это степень, узлы и определяющие точки

>>По поводу 2, то есть дуг в полилиниях. Ты не думал сделать средний слой, чтобы не переделывать нижний уровень движка?
Конечно думал)) рано или поздно руки дойдут https://github.com/zamtmn/zcad/issues/4

>>Написать функцию для нахождения произвольной точки по параметру t, где 0 <= t <= 1, вообще не проблема.
Для меня оказалась проблема даже в общем случае, о скорости и точности вообще молчу((
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: САПР на Lazarus

Сообщение MylnikovDm » 06.03.2020 14:52:27

Посмотрел, что по этому поводу пишут в документации по команде spline https://knowledge.autodesk.com/support/ ... 8-htm.html

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

Также я понял, как они делают режим fit. Если у нас b-spline третьего порядка, то если поставить подряд три управляющие точки в одном месте, то сплайн пройдёт через данную точку. Так что в режиме fit просто а данной точке сразу ставится три управляющие точки, а в обычном режиме одна. Соответственно, через этот метод делается и переход от режима fit к режиму CV (Control Vertices). То есть, тут тоже нет ничего сложного, если немного покурить теорию по сплайнам. :) Нужен режим fit, повтоярешь в наборе контрольных точек одну и туже точку 3 раза. Нужен режим CV, удаляешь повторяющиеся точки из набора.

Единственное, с чем пока не разобрался, так это с тем, как они фиксируют угол начала и конца кривой (есть там такая опция при построении сплайна). Хотя, если вспомнить теорию по кривым Безье, то там кривая всегда является касательной к линии, которая соединяет управляющие точки. Так что, скорее всего, просто добавляют ещё одну невидимую управляющую точку, которая задаёт угол начального и конечного сегмента. Но это надо пробовать.
MylnikovDm
постоялец
 
Сообщения: 103
Зарегистрирован: 15.02.2007 21:26:10
Откуда: Челябинск

Re: САПР на Lazarus

Сообщение zub » 06.03.2020 16:20:19

>>Нужен режим fit, повтоярешь в наборе контрольных точек одну и туже точку 3 раза. Нужен режим CV, удаляешь повторяющиеся точки из набора.
при переключении режимов сплайн не меняется, остается такимже. (покрайней мере глазу незаметно)

Также в свойствах сплайна можно менять degree в сторону увеличения, уменьшить нельзя. При этом увеличивается количество CV. Потом если переключить способ в fit и обратно в cv - колво cv не изменится а degree станет снова 3

Касательная в автокаде не задается для крайних точек емнип. Да, скорее всего както выщитывается на основе крайних точек
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: САПР на Lazarus

Сообщение Mirage » 24.03.2020 18:24:03

Случаи, когда кривая (речь о кубических) задается 4 точками и 2 точками плюс 2 касательными, эквивалентны. Очевидно, что в первом (называется Кэтмулл-Ром сплайном) кривая проходит через все 4 точки, а во втором - через 2, а в 2-х остальных имеет указанные касательные.
Есть разные вариации, но в целом задаются одной тривиальной формулой - полиномом 3-й степени. Разница лишь в том, как считаются коэффициенты. Поэтому переключение режима с fit/cp - также тривиально. Для одной и той же кривой, независимо от режима, коэффициенты, естественно, одинаковые получаются.
Ближайшую точку на кривой аналитически не находят, т.к. сложно. Находят приближенно, итерацией по кривой, затем уточняют аналитически, если надо.
Что касается середины и т.п., то точка t=0.5 это не середина кривой линии, как правило. Середину посчитать не так просто. Тоже итерироваться придется.
Вообще, промежуток, где t=[0..1] это только сегмент сплайна. Сам сплайн состоит из многих таких кусков, если точек больше 4-х.
У меня есть либа для кубических сплайнов, заточенная пока под Кэтмулл-Ром сплайны. Ближайшую точку кривой к заданной находить умеет. Могу поделиться.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: САПР на Lazarus

Сообщение zub » 25.03.2020 13:43:59

>>Могу поделиться.
А можешь не поделиться?))
Поделись пжст. я хоть к сплайнам непланировал пока возвращаться, но всеже
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: САПР на Lazarus

Сообщение Mirage » 02.04.2020 18:15:54

Сори за задержку, редко захожу сюда теперь. Вот:
https://github.com/casteng/g3commons/bl ... spline.pas
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: САПР на Lazarus

Сообщение zub » 06.04.2020 00:36:58

спасибо. срисовал в накопилку
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: САПР на Lazarus

Сообщение zub » 28.07.2020 01:03:21

Наконец зкад заработал в стабильном релизе лазаря laz2.0.10 + fpc3.2
В дальнейшем постараюсь поддерживать совместимость с релизами
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: САПР на Lazarus

Сообщение Pavia » 28.07.2020 10:16:51

Посмотрел ваш проект. И у меня возник вопрос. Вы копируете интерфейс Автокада, но это очень неудобная штука. Зачем?
Не лучше ли использовать Визио, или Солидвокс?
Аватара пользователя
Pavia
постоялец
 
Сообщения: 290
Зарегистрирован: 07.01.2011 12:46:51

Re: САПР на Lazarus

Сообщение veb86 » 28.07.2020 10:51:25

Pavia писал(а):Посмотрел ваш проект. И у меня возник вопрос. Вы копируете интерфейс Автокада, но это очень неудобная штука. Зачем?
Не лучше ли использовать Визио, или Солидвокс?

Ну тут на вкус и цвет. Как по мне так интерфейс автокад2008 самый удобный был.
veb86
новенький
 
Сообщения: 62
Зарегистрирован: 16.03.2016 12:58:35

Пред.След.

Вернуться в Разработки на нашем сайте

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

Сейчас этот форум просматривают: Yandex [Bot] и гости: 2

Рейтинг@Mail.ru