program GCodeGenerator; uses SysUtils, StrUtils, Math; type TPoint = record X, Y: double; end; type TStatorParams = record BaseDiameter: Double; NumberOfRays: Integer; RayShape: string; RayDiameter: Double; RayWidth: Double; RayHeight: Double; RayLength: Double; RayTopShape: string; RayTopDiameter: Double; RayTopWidth: Double; RayTopHeight: Double; RayCenterOffset: Double; WireDiameter: Double; NeedleDiameter: Double; PathClearance: Double; WorkSpeed :integer; end; var InputFileName, OutputFileName: string; StatorParams: TStatorParams; InFile, OutFile: TextFile; Line: string; CoilRadius :double; CurrentZ: double; coords: TPoint; normalizecoords: TPoint; i, j, k: Integer; CurrentCoilTurns :Integer; AngleBetweenRays :double; RequiredSpacing: Double; LayerNumber :Integer; angle : double; function ParseLine(Line: string): Boolean; var Parts: array of string; Value: string; TrimmedLine: string; begin TrimmedLine := Trim(Line); // Удаляем пробелы в начале и конце строки if Length(TrimmedLine) = 0 then begin exit(true); // Пустая строка - пропускаем end else if TrimmedLine[1] in [';','#'] then begin exit(true); // Строка комментария - пропускаем end; Parts := SplitString(TrimmedLine, '='); // Используем TrimmedLine Result := Length(Parts) = 2; if Result then begin Value := LowerCase(Trim(Parts[1])); // Приводим к нижнему регистру case Trim(Parts[0]) of 'base_dia': begin StatorParams.BaseDiameter := StrToFloat(Value); writeln('Base Diameter: ', StatorParams.BaseDiameter:8:2); writeln(); end; 'num_rays': begin StatorParams.NumberOfRays := StrToInt(Value); writeln('Number of Rays: ', StatorParams.NumberOfRays); AngleBetweenRays := 360/StatorParams.NumberOfRays; writeln('Angle Between Rays: ', AngleBetweenRays); writeln(); end; 'ray_shape': begin if Pos(Value, 'circle, rect, superellipse') = 0 then raise Exception.Create('Invalid value for ray_shape: ' + Value); StatorParams.RayShape := Value; writeln('Ray Shape: ', StatorParams.RayShape); writeln(); end; 'ray_dia': begin StatorParams.RayDiameter := StrToFloat(Value); writeln('Ray Diameter: ', StatorParams.RayDiameter:8:2); writeln(); end; 'ray_w': begin StatorParams.RayWidth := StrToFloat(Value); writeln('Ray Width: ', StatorParams.RayWidth:8:2); writeln(); end; 'ray_h': begin StatorParams.RayHeight := StrToFloat(Value); writeln('Ray Height: ', StatorParams.RayHeight:8:2); writeln(); end; 'ray_len': begin StatorParams.RayLength := StrToFloat(Value); writeln('Ray Length: ', StatorParams.RayLength:8:2); writeln(); end; 'raytop_shape': begin if Pos(Value, 'circle, rect, superellipse') = 0 then raise Exception.Create('Invalid value for ray_top: ' + Value); StatorParams.RayTopShape := Value; writeln('Ray Top Shape: ', StatorParams.RayTopShape); end; 'raytop_dia': begin StatorParams.RayTopDiameter := StrToFloat(Value); writeln('Ray Top Diameter: ', StatorParams.RayTopDiameter:8:2); writeln(); end; 'raytop_w': begin StatorParams.RayTopWidth := StrToFloat(Value); writeln('Ray Top Width: ', StatorParams.RayTopWidth:8:2); writeln(); end; 'raytop_h': begin StatorParams.RayTopHeight := StrToFloat(Value); writeln('Ray Top Height: ', StatorParams.RayTopHeight:8:2); writeln(); end; 'ray_offset': begin StatorParams.RayCenterOffset := StrToFloat(Value); writeln('Ray Center Offset: ', StatorParams.RayCenterOffset:8:2); writeln(); end; 'wire_diameter': begin StatorParams.WireDiameter := StrToFloat(Value); writeln('Wire Diameter: ', StatorParams.WireDiameter:8:2); writeln(); end; 'needle_diameter': begin StatorParams.NeedleDiameter := StrToFloat(Value); writeln('Needle Diameter: ', StatorParams.NeedleDiameter:8:2); writeln(); end; 'path_clearance': begin StatorParams.PathClearance := StrToFloat(Value); writeln('Path Clearance: ', StatorParams.PathClearance:8:2); writeln(); end; 'work_speed': begin StatorParams.WorkSpeed := StrToInt(Value); writeln('Work Speed: ', StatorParams.WorkSpeed); writeln(); end; else Result := False; end; if not Result then begin writeln('Error: Unknown parameter: ', Parts[0]); exit; end; end; end; function CircleCoordinates(diameter, angleDegrees: Double): TPoint; var radius: Double; angleRadians: Double; begin radius := diameter / 2; // angleRadians := -1*angleDegrees * PI / 180; // Перевод градусов в радианы angleRadians := -1 * DegToRad(angleDegrees); Result.X := radius * Cos(angleRadians); Result.Y := radius * Sin(angleRadians); end; function CalculateAngle(opposite, adjacent: Double): Double; begin if adjacent = 0 then raise Exception.Create('Adjacent side cannot be zero'); // CalculateAngle := ArcTan(opposite / adjacent) * 180 / PI; CalculateAngle := RadToDeg(ArcTan(opposite / adjacent)); end; (* //ToDO Переписать функцию, чтобы она возвращала только одно значение Z. Нам же нужно исправлять только одну координату. function NormalizeZ(xOkr, yOkr, radius: Real; thetaDeg: Real): TPoint; var thetaRad, thetaCorrRad, xKas, yKas, alphaRad, mTang, bTang, mHor, xPrym, yPrym: Real; begin thetaRad := DegToRad(thetaDeg); ;thetaCorrRad := thetaRad + DegToRad(270); // 1. Координаты точки касания xKas := radius * Cos(thetaCorrRad); yKas := radius * Sin(thetaCorrRad); // 2. Угол наклона касательной alphaRad := thetaCorrRad + PI / 2; // 3. Уравнение касательной (y = m*x + b) mTang := Tan(alphaRad); bTang := yKas - mTang * xKas; // 4. Уравнение горизонтальной прямой mHor := Tan(alphaRad - PI/2); // 5. Точка пересечения xPrym := (bTang + yOkr + mHor * xOkr)/(mHor - mTang); yPrym := mTang * xPrym + bTang; NormalizeZ.x := xPrym; NormalizeZ.y := yPrym; //Writeln('thetaDeg =',thetaDeg:0:2,' ,xKas = ',xKas:0:2,' ,yKas = ',yKas:0:2); Writeln('thetaDeg =',thetaDeg:0:2,' ,xPrym = ',xPrym:0:2,' ,yPrym = ',yPrym:0:2); end; *) function NormalizeZ(radius: Real; thetaDeg: Real): Real; var thetaRad, alphaRad, xKas, yKas, mTang, bTang: Real; begin // 1. Преобразование угла из градусов в радианы. thetaRad := DegToRad(thetaDeg); // 2. Вычисление координат точки касания на окружности (относительно центра 0,0). xKas := radius * Cos(thetaRad); yKas := radius * Sin(thetaRad); // 3. Вычисление угла, перпендикулярного радиус-вектору (касательной). alphaRad := thetaRad + PI / 2; // 4. Вычисление углового коэффициента касательной. mTang := Tan(alphaRad); // 5. Вычисление свободного члена уравнения касательной (y = mTang * x + bTang). bTang := yKas - mTang * xKas; // 6. Вычисление координаты X точки пересечения касательной с осью X (y = 0). // 0 = mTang * x + bTang // x = -bTang / mTang if mTang = 0 then begin // Касательная параллельна оси X - нет точки пересечения. Возвращаем NaN. NormalizeZ := NaN; end else begin NormalizeZ := -bTang / mTang; end; end; begin // Command line argument handling if ParamCount < 2 then begin Writeln('Usage: GCodeGenerator '); Halt(1); end; InputFileName := ParamStr(1); OutputFileName := ParamStr(2); // **Opening the input file** AssignFile(InFile, InputFileName); try Reset(InFile); // **This line opens the file for reading** while not EOF(InFile) do begin ReadLn(InFile, Line); if Length(Line) > 0 then if not ParseLine(Line) then writeln('Error: Invalid line: ', Line); end; except on E: Exception do begin writeln('Error opening or reading input file: ', E.Message); Halt(1); end; end; CloseFile(InFile); // G-code generation AssignFile(OutFile, OutputFileName); try Rewrite(OutFile); // *** Your G-code generation logic here *** writeln(OutFile, '; G-code for stator winding'); writeln(OutFile, 'G90 ; Absolute coordinate system'); writeln(OutFile, 'G1 Y-10'); writeln(OutFile, 'G28 X Y Z'); writeln(OutFile, 'G1 X0 Y0'); //writeln(OutFile, 'G28 O'); //Home all "untrusted" axes writeln(OutFile); // Move to center of ray along Y axis and reset coordinate writeln(OutFile, 'G1 X', StatorParams.RayCenterOffset:0:2); writeln(OutFile, 'G92 X0'); //отводим иглу левее вершины луча CoilRadius:=(StatorParams.RayTopHeight/2+StatorParams.NeedleDiameter/2+StatorParams.PathClearance); writeln('CoilRadius = ', CoilRadius:0:3); writeln(OutFile, 'G1 X', -1*CoilRadius:0:3); //приближаемся к основанию статора. CurrentZ:=(StatorParams.BaseDiameter/2)+StatorParams.PathClearance; writeln(OutFile, 'G1 Z', CurrentZ:0:2, ' F', StatorParams.WorkSpeed); writeln(OutFile, 'M0'); writeln(OutFile, ';Start coil'); //Делаем круг. Inc(LayerNumber); CurrentCoilTurns := round(StatorParams.RayLength/StatorParams.WireDiameter); // CurrentCoilTurns := 1; writeln(OutFile, ';We make ',CurrentCoilTurns, ' turns' ); for j := 0 to CurrentCoilTurns do begin for i := 0 to 360 do begin coords := CircleCoordinates(CoilRadius*2, i+180); writeln(OutFile,'CoilRadius*2= ',CoilRadius*2:0:5,' X=', coords.X:0:3, ' Y=', coords.Y:0:5); angle := CalculateAngle(coords.Y, CurrentZ); // writeln(OutFile, ';G1 X', coords.X:0:3, ' Y', angle:0:5,' Z', CurrentZ:0:5); writeln(OutFile, 'G1 X', coords.X:0:3, ' Y', angle:0:5,' Z', NormalizeZ(CurrentZ, angle):0:5); // writeln(OutFile); CurrentZ:=CurrentZ+StatorParams.WireDiameter/360; end; writeln(OutFile, ';Next coil.'); end; writeln(OutFile, ';Second coil'); Inc(LayerNumber); // RequiredSpacing:=StatorParams.RayWidth+StatorParams.NeedleDiameter+StatorParams.PathClearance*2+LayerNumber*StatorParams.WireDiameter*2; // writeln(OutFile, ';RequiredSpacing = ',RequiredSpacing:0:5); RequiredSpacing:=StatorParams.RayTopWidth; writeln(OutFile, ';RequiredSpacing = ',RequiredSpacing:0:5); RequiredSpacing:=RequiredSpacing+StatorParams.NeedleDiameter; writeln(OutFile, ';RequiredSpacing = ',RequiredSpacing:0:5); RequiredSpacing:=RequiredSpacing+StatorParams.PathClearance*2+LayerNumber*StatorParams.WireDiameter*2; writeln(OutFile, ';RequiredSpacing = ',RequiredSpacing:0:5); CurrentZ:=RequiredSpacing/(2 * tan(AngleBetweenRays*PI/180/2)); writeln(OutFile, ';CurrentZ = ',CurrentZ:0:3); // *** Your G-code generation logic here *** except on E: Exception do begin writeln('Error writing to output file: ', E.Message); Halt(1); end; end; CloseFile(OutFile); writeln('G-code generated to: ', OutputFileName); writeln('Press Enter... '); Readln; end.