Wątek przeniesiony 2017-09-09 16:25 z Java przez furious programming.

Rysowanie elementu z kodu maszyny CNC

0

Próbuję zrobić program który w tekście np (G01 X100.0 Z50.0) wyszukuje X i cyfrę i Z i cyfrę po to żeby wydobyć cyfry które potem posłużą do rysowania w canvas. Mam problem w poniższym kodzie który może jest nie fachowo napisany bo jestem początkującym, z przypadkiem kiedy pętla natrafia na linię gdzie NIE MA X i Z i jak zrobić żeby program przeskoczył do następnej linii i jeśli jest tylko jedna X lub Z to program ma pozostawić wartość tej której NIE MA z poprzedniej linii. Obecnie brak Z lub X powoduje błąd. Może ktoś już się zajmował tym zadaniem, może moje podejście do tego zadania jest błędne to proszę o jakieś rady jak do tego najlepiej podejść.

procedure TForm1.lb711Click(Sender: TObject);
var
  liczbax, liczbaz: double;
  I, xx, zz, x2, z2: integer;
 // g:extended;
  text: string;
  Z, X: string;
begin
   form9.image1.Picture:= nil;
   form9.image1.Canvas.Pen.Style :=psDashDot;
   form9.image1.Canvas.MoveTo(500, 0);
   form9.image1.Canvas.lineTo(500, 600);// rysuje oś X
   form9.image1.Canvas.MoveTo(0, 400);
   form9.image1.Canvas.lineTo(1000, 400);// rysuje oś Z
    form9.image1.Canvas.Pen.Width :=2;
   form9.image1.Canvas.Pen.Style :=pssolid;
  // showmessage(inttostr((ActiveMDIChild as TForm2).syndt1.Lines.Count));
  form9.Show;

  form9.image1.Canvas.MoveTo(180, 150);// poczatek malowania linii
  //Z := '';
  for I := 0 to (ActiveMDIChild as TForm2).syndt1.Lines.Count -1 do
  begin

    text := (ActiveMDIChild as TForm2).syndt1.Lines[I]; // pobranie zawartości linii

    if length(TEXT) <> 0 then
    begin
      try
        Z := TRegEx.Match(text, 'Z[+-]?[0-9]+(\.[0-9]+)').Value; //pobranie z tekstu np Z100.6
        X := TRegEx.Match(text, 'X[+-]?[0-9]+(\.[0-9]+)').Value;


        delete(Z, 1, 1);// wymazanie z z pobranego tekstu np (Z100.0)pozostaje 100.0
        delete(X, 1, 1);
      except
	//on E: ERegularExpressionError do begin
		// Syntax error in the regular expression }
      end;

      x := stringreplace((x), '.', ',', [rfreplaceall, rfignorecase]);//zmiana kropki na przecinek
        showmessage(x);
      liczbax := strtofloat(x);
      xx := round(liczbax*100); //likwidacja liczb po przecinku z ich przesunieciem o dwa miejsca 


      z := stringreplace((z), '.', ',', [rfreplaceall, rfignorecase]);
      liczbaz := strtofloat(z);
      zz := round(liczbaz*100);

      form9.image1.Canvas.LineTo(xx, zz);
    end;
  end;
end;
0
loza napisał(a):

Próbuję zrobić program który w tekście np (G01 X100.0 Z50.0) wyszukuje X i cyfrę i Z i cyfrę po to żeby wydobyć cyfry które potem posłużą do rysowania w canvas.

Nie cyfrę, a liczbę rzeczywistą – nazywaj rzeczy po imieniu.

[…] z przypadkiem kiedy pętla natrafia na linię gdzie NIE MA X i Z i jak zrobić żeby program przeskoczył do następnej linii i jeśli jest tylko jedna X lub Z to program ma pozostawić wartość tej której NIE MA z poprzedniej linii.

Strasznie niezgrabnie to tłumaczysz. Myślę że chodzi o to, że wartości X i Z mogą być zapisane w jednej lub w dwóch liniach, a algorytm ma działać prawidłowo dla obu przypadków. Racja?


Najpierw powinieneś pobrać linię tekstu. Następnie taką linię należy poddać walidacji – sprawdzić które wartości znajdują się w niej i zwrócić stan do głównego kodu. Jeśli w bieżącej linii którejś współrzędnej brakuje, to powinieneś pobrać kolejną linię i w niej poszukać brakujących danych.

Potrzebujesz metody, która pobierze w parametrze ciąg znaków linii i zwróci informację o tym, które współrzędne się w niej znajdują. Przyda się też osobna metoda, która umożliwi ekstrakcję współrzędnej z zadanej linii. Możesz to załatwić regexem, dlatego że jeśli ten nie znajdzie dopasowania to zapewne zwróci pusty ciąg znaków – i to jest informacja o braku zadanej współrzędnej.


Jeśli mowa o Twoim kodzie – bajzel w nim straszny i wymaga podzielenia na mniejsze fragmenty. Blok try except przy operacjach na regexach jest zbędny – przecież masz je hardkodowane, więc chyba potrafisz określić ich bezbłędność?

Kolejna rzecz to zmiana znaków w ciągu, za pomocą StringReplace. Używasz w niej flagi rfIgnoreCase, co jest zbędne, bo znaki które zamieniasz, nie posiadają wielkiej i małej postaci. Tę flagę używa się do liter, nie znaków interpunkcyjnych. Zamiast wymieniać separator na inny, równie dobrze możesz skorzystać z uniwersalnej pseudoprocedury Val, które obsługuje kropkę jako separator.

Ostatnia rzecz to nazwy formularzy i kontrolek – form9, image1 i syndt1 to nie są dobre identyfikatory, bo absolutnie nic nie mówią o przeznaczeniu tych obiektów. Tak więc nadaj konkretne nazwy wszystkim kontrolkom, a praca z kodem stanie się łatwiejsza.

0

Dziękuję bardzo za rady na pewno z nich skorzystam i przepraszam za ten kod na pewno masz racje w tym ze to totalny bajzel, ale na błędach się człowiek uczy. Pracuję na obrabiarkach numerycznych sterowanie Fanuc i próbuję ułatwić sobie pracę aby z programu do obrabiarki wydobyć wartości współrzędnych X i Z i za pomocą canvas zobaczyć proces obróbki. Jak na mnie jest to trudne zadanie bo dopiero zaczynam przygodę z delphi.

0

Łatwiej by było, gdybyś podał przykładową zawartość kontrolki syndt1 – wtedy mógłbym coś podłubać u siebie i mieć pewność, że rozwiązanie będzie działać prawidłowo.

0

Podam typowy program do cnc bo to on będzie w kontrolce synedt1

:0049(SHEAR SCREW M18X1.5) 
N10(ISS A/C-P=20.0)
N20G00G21G40G99
N30G50S2700
N40G10P0Z-40.0 
N50T1212(STOP) 
N60G00X10.0Z10.0 
N70G200Z-20.0R0.4
N80G00X150.0Z160.0M01
N90T0303(PCLNR 0.8)
N100G00G96S220F0.05M13 
N110X21.0Z0.2
N120G01X-1.0 
N130G00X20.5Z1.0 
N140G71U1.5R1.0
N150G71P160Q210U0.2W0.1F0.1
N160G00X14.0 
N170G01Z0.1
N180G01X15.298A135.0F0.01
N190G01Z-19.999F0.05 
N200G01X17.8A135.0 
N210G01Z-32.0
N220G00X150.0Z160.0M01 
N230T0909(MTJNR 0.4) 
N240G00G96S300F0.05M13 
N250X20.5Z0.0
N260G01X-1.5 
N270G00X20.5Z0.5 
N280G70P160Q210
N290G00X150.0Z150.0M01 
N300T0505(1.17MM P/OFF)
N310G00G97X15.5Z-15.0S700F0.03M13
N320G01X13.26
N330G00X15.4 
N340G00Z-13.8
N350G01X12.7 
N360G00X15.4 
N370G00Z-13.77 
N380G01X13.26
N390G00X15.4 
N395G01Z-13.57X15.3F0.01 
N400G03X14.9Z-13.77R0.2
N410G01X13.26
N420G02X12.66Z-14.07R0.3 
N430G01Z-14.7S400F0.04 
N431G00X15.4 
N432G00Z-15.2X15.3 
N433G02X14.9Z-15.0R0.2F0.01
N434G01X13.26
N435G03X12.66Z-14.7R0.3
N436G00X17.0 
N440G00X150.0Z150.0M01 
N450T1111(2MM PART OFF)
N455G00G96X20.0Z-31.0S300F0.05M13
N460G01X15.0F0.05
N470G00X18.0 
N480G00Z-29.5
N490G01Z-31.0A225
N500G00X20.0 
N510G00X150.0Z150.0M01 
N520T0707(M18X1.5) 
N530G00G97X18.5Z-18.0S500M13 
N540G76P020060Q100R0.05
N550G76X16.5Z-30.0P750Q100F1.5 
N560G00X150.0Z150.0M01 
N570T1111(2MM P/OFF) 
N580G00G96Z-29.5X20.0S300F0.05M13
N582G01X18.0 
N584G01Z-31.0A225M70 
N590G01X5.0
N600G01G97S300X0.0 
N610G00X25.0M74
N620X100.0Z160.0M01
N630M05
N640M09
N650M99

Jak można zauważyć są linie które są tylko komentarzem i linie w których występuje X i Z lub samo X. To tak jak ruch po osi współrzędnych. Są też specjalne funkcje które jak np G76 do obróbki gwintów która w sobie zawiera z kilkanaście linii i aby to wyrysować to trzeba będzie stworzyć osobny podprogram do rozpisania go ale to w dalszej części.

1

nudziło mnie się :p

unit MainForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, SynEdit,
  SynMemo;

type
  TfrmMain = class(TForm)
    mmoProgram: TSynMemo;
    pbDrawBox: TPaintBox;
    pnlButtons: TPanel;
    btnDraw: TButton;
    procedure FormCreate(Sender: TObject);
    procedure pbDrawBoxPaint(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure btnDrawClick(Sender: TObject);
  private
    FBuffer: TBitmap;
    procedure ClearBuffer;
    procedure DrawCNC;
    procedure ValFromStr(const str, find: string; var Val: Double);
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure TfrmMain.btnDrawClick(Sender: TObject);
begin
  ClearBuffer;
  DrawCNC;
end;

procedure TfrmMain.ClearBuffer;
const
  GridSize = 20;
var
  i: Integer;
begin
  with FBuffer, Canvas do
  begin
    //wypełnienie na biało
    Brush.Color := clWhite;
    Brush.Style := bsSolid;
    FillRect(Rect(0, 0, Width, Height));
    //obrys dookoła
    Pen.Style := psSolid;
    Pen.Color := clBlack;
    Pen.Width := 1;
    Rectangle(1, 1, Width - 2, Height - 2);
    //oś X
    MoveTo(1, Height div 2);
    LineTo(Width - 2, Height div 2);
    //oś Y
    MoveTo(Width div 2, 1);
    LineTo(Width div 2, Height - 2);
    //siatka
    Pen.Style := psDot;
    pen.Color := clSilver;
    for i := 1 to Height div GridSize * 2 do
    begin
      //siatka linie poziome
      MoveTo(1, Height div 2 - i * GridSize);
      LineTo(Width - 2, Height div 2 - i * GridSize);
      MoveTo(1, Height div 2 + i * GridSize);
      LineTo(Width - 2, Height div 2 + i * GridSize);
      //siatka linie pionowe
      MoveTo(Width div 2 - i * GridSize, 1);
      LineTo(Width div 2 - i * GridSize, Height - 2);
      MoveTo(Width div 2 + i * GridSize, 1);
      LineTo(Width div 2 + i * GridSize, Height - 2);
    end;
  end;
end;

procedure TfrmMain.DrawCNC;
var
  X, Z: Double;
  dX, dY: Integer;
  i: Integer;
  s: string;
begin
  with FBuffer, Canvas do
  begin
    Pen.Color := clBlue;
    Pen.Style := psSolid;
    dX := Width div 2;
    dy := Height div 2;
    X := dX;
    Z := dY;

    MoveTo(Round(X), Round(Z));
    for s in mmoProgram.Lines do
    begin
      ValFromStr(s, 'X', X);
      ValFromStr(s, 'Z', Z);
      LineTo(Round(X) + dX, Round(Z) + dY);
    end;
  end;
  pbDrawBox.Refresh;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  FBuffer := TBitmap.Create;
  FBuffer.Width := pbDrawBox.ClientWidth;
  FBuffer.Height := pbDrawBox.Height;

  ClearBuffer;
end;

procedure TfrmMain.FormResize(Sender: TObject);
begin
  FBuffer.Width := pbDrawBox.ClientWidth;
  FBuffer.Height := pbDrawBox.Height;

  ClearBuffer;
end;

procedure TfrmMain.ValFromStr(const str, find: string; var Val: Double);
var
  b, e, i: Integer;
begin
  b := Pos(find, str);
  if b > 0 then
  begin
    Inc(b);
    e := b;
    while str[e] in ['0'..'9', '.', '-'] do
      Inc(e);
    Val := StrToFloat(StringReplace(Copy(str, b, e- b), '.', FormatSettings.DecimalSeparator, [rfReplaceAll]));
  end;
end;

procedure TfrmMain.pbDrawBoxPaint(Sender: TObject);
begin
  pbDrawBox.Canvas.Draw(0, 0, FBuffer);
end;

end.

(https://4programmers.net/Forum/Download/16610)4p1.png

Cały projekt w załączniku

0

Dziękuję bardzo, program widzę zrobiony fachowo, ja bym tego nigdy nie zrobił. Wszystko jest ok tylko troche w złym miejscu rysuje pionowa oś to oś X, pozioma to oś Z, z tym że -Z powinno rysować od środka na lewo i w górnej części.

0

To tylko przykład – nie wiemy przecież jak chcesz aby to wyglądało (no, teraz wiemy).

Jak coś jest w złym miejscu rysowane to dodaj sobie offsety, a jak po złej stronie osi to zmień znak współrzędnej.

0

W Lazarus-ie jest biblioteka fpvectorial http://wiki.lazarus.freepascal.org/fpvectorial
umożliwiająca zapis i odczyt i rysowanie plików w formacie G-Code.

1 użytkowników online, w tym zalogowanych: 0, gości: 1