Import LinuxCNC source tree
This commit is contained in:
315
lib/python/plasmac/line.py
Normal file
315
lib/python/plasmac/line.py
Normal file
@@ -0,0 +1,315 @@
|
||||
'''
|
||||
line.py
|
||||
|
||||
Copyright (C) 2020 - 2024 Phillip A Carter
|
||||
Copyright (C) 2020 - 2024 Gregory D Carl
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
'''
|
||||
|
||||
import os
|
||||
import sys
|
||||
import math
|
||||
import numpy
|
||||
import gettext
|
||||
|
||||
for f in sys.path:
|
||||
if '/lib/python' in f:
|
||||
if '/usr' in f:
|
||||
localeDir = 'usr/share/locale'
|
||||
else:
|
||||
localeDir = os.path.join(f'{f.split("/lib")[0]}', 'share', 'locale')
|
||||
break
|
||||
gettext.install("linuxcnc", localedir=localeDir)
|
||||
|
||||
|
||||
# Conv is the upstream calling module
|
||||
def do_line_point_to_point(Conv, xStart, yStart, xEnd, yEnd):
|
||||
error = ''
|
||||
msg1 = _('entry is invalid')
|
||||
valid, xStart = Conv.conv_is_float(xStart)
|
||||
if not valid and xStart:
|
||||
msg0 = _('X START')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, yStart = Conv.conv_is_float(yStart)
|
||||
if not valid and yStart:
|
||||
msg0 = _('Y START')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, xEnd = Conv.conv_is_float(xEnd)
|
||||
if not valid and xEnd:
|
||||
msg0 = _('X END')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, yEnd = Conv.conv_is_float(yEnd)
|
||||
if not valid and yEnd:
|
||||
msg0 = _('Y END')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
if error:
|
||||
return True, error
|
||||
if xEnd == xStart and yEnd == yStart:
|
||||
msg = _('Line length would be zero')
|
||||
error += f'{msg}\n\n'
|
||||
if error:
|
||||
return True, error
|
||||
code = f'G01 X{float(xEnd):.6f} Y{float(yEnd):.6f}\n'
|
||||
return False, xEnd, yEnd, code
|
||||
|
||||
|
||||
def do_line_by_angle(Conv, xStart, yStart, length, angle):
|
||||
error = ''
|
||||
msg1 = _('entry is invalid')
|
||||
valid, xStart = Conv.conv_is_float(xStart)
|
||||
if not valid and xStart:
|
||||
msg0 = _('X START')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, yStart = Conv.conv_is_float(yStart)
|
||||
if not valid and yStart:
|
||||
msg0 = _('Y START')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, length = Conv.conv_is_float(length)
|
||||
if not valid and length:
|
||||
msg0 = _('LENGTH')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, angle = Conv.conv_is_float(angle)
|
||||
if not valid and angle:
|
||||
msg0 = _('ANGLE')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
if error:
|
||||
return True, error
|
||||
if length == 0:
|
||||
msg = _('LENGTH must be greater than zero')
|
||||
error += f'{msg}\n\n'
|
||||
if error:
|
||||
return True, error
|
||||
ang = math.radians(angle)
|
||||
x = xStart + (length * math.cos(ang))
|
||||
y = yStart + (length * math.sin(ang))
|
||||
code = f'G01 X{x:.6f} Y{y:.6f}\n'
|
||||
return False, x, y, code
|
||||
|
||||
|
||||
def do_arc_3_points(Conv, xStart, yStart, xNext, yNext, xEnd, yEnd):
|
||||
error = ''
|
||||
msg1 = _('entry is invalid')
|
||||
valid, xStart = Conv.conv_is_float(xStart)
|
||||
if not valid and xStart:
|
||||
msg0 = _('X START')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, yStart = Conv.conv_is_float(yStart)
|
||||
if not valid and yStart:
|
||||
msg0 = _('Y START')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, xNext = Conv.conv_is_float(xNext)
|
||||
if not valid and xNext:
|
||||
msg0 = _('X NEXT')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, yNext = Conv.conv_is_float(yNext)
|
||||
if not valid and yNext:
|
||||
msg0 = _('Y NEXT')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, xEnd = Conv.conv_is_float(xEnd)
|
||||
if not valid and xEnd:
|
||||
msg0 = _('X END')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, yEnd = Conv.conv_is_float(yEnd)
|
||||
if not valid and yEnd:
|
||||
msg0 = _('Y END')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
if error:
|
||||
return True, error
|
||||
if xNext == xEnd == xStart:
|
||||
msg = _('At least one X value must be different')
|
||||
error += f'{msg}\n\n'
|
||||
if yNext == yEnd == yStart:
|
||||
msg = _('At least one Y value must be different')
|
||||
error += f'{msg}\n\n'
|
||||
if xNext == yNext and xEnd == yEnd and xStart == yStart:
|
||||
msg = _('Cannot create a arc, check all entries')
|
||||
error += f'{msg}\n\n'
|
||||
if error:
|
||||
return True, error
|
||||
try:
|
||||
A = numpy.array([xStart, yStart, 0.0])
|
||||
B = numpy.array([xNext, yNext, 0.0])
|
||||
C = numpy.array([xEnd, yEnd, 0.0])
|
||||
a = numpy.linalg.norm(C - B)
|
||||
b = numpy.linalg.norm(C - A)
|
||||
c = numpy.linalg.norm(B - A)
|
||||
b1 = a*a * (b*b + c*c - a*a)
|
||||
b2 = b*b * (a*a + c*c - b*b)
|
||||
b3 = c*c * (a*a + b*b - c*c)
|
||||
p = numpy.column_stack((A, B, C)).dot(numpy.hstack((b1, b2, b3)))
|
||||
p /= b1 + b2 + b3
|
||||
G = '03' if (xNext - xStart) * (yEnd - yStart) - (yNext - yStart) * (xEnd - xStart) > 0 else '02'
|
||||
if numpy.isnan(p[0] - xStart) or numpy.isnan(p[1] - yStart):
|
||||
msg0 = _('Unknown calculation error')
|
||||
msg1 = _('Ensure entries are correct')
|
||||
error = f'{msg0},\n\n{msg1}'
|
||||
return True, error
|
||||
code = f'G{G} X{xEnd:.6f} Y{yEnd:.6f} I{p[0] - xStart:.6f} J{p[1] - yStart:.6f}\n'
|
||||
return False, xEnd, yEnd, code
|
||||
except Exception as e:
|
||||
msg = _('SYSTEM ERROR')
|
||||
error = f'{msg}:\n\n{e}'
|
||||
return True, e
|
||||
|
||||
|
||||
def do_arc_2_points_radius(Conv, xStart, yStart, xEnd, yEnd, radius, arcType):
|
||||
error = ''
|
||||
msg1 = _('entry is invalid')
|
||||
valid, xStart = Conv.conv_is_float(xStart)
|
||||
if not valid and xStart:
|
||||
msg0 = _('X START')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, yStart = Conv.conv_is_float(yStart)
|
||||
if not valid and yStart:
|
||||
msg0 = _('Y START')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, xEnd = Conv.conv_is_float(xEnd)
|
||||
if not valid and xEnd:
|
||||
msg0 = _('X END')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, yEnd = Conv.conv_is_float(yEnd)
|
||||
if not valid and yEnd:
|
||||
msg0 = _('Y END')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, radius = Conv.conv_is_float(radius)
|
||||
if not valid and radius:
|
||||
msg0 = _('RADIUS')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
if error:
|
||||
return True, error
|
||||
if radius == 0:
|
||||
msg = _('RADIUS cannot be zero')
|
||||
error += f'{msg}\n\n'
|
||||
if xEnd == xStart and yEnd == yStart:
|
||||
msg = _('Arc length would be zero')
|
||||
error += f'{msg}\n\n'
|
||||
if error:
|
||||
return True, error
|
||||
try:
|
||||
dir = math.radians(270) if radius > 0 else math.radians(90)
|
||||
height = math.sqrt((xEnd - xStart) ** 2 + (yEnd - yStart) ** 2) * 0.5
|
||||
if radius < height:
|
||||
return True, _('Radius must be at least half the length')
|
||||
length = math.sqrt((radius ** 2) - (height ** 2))
|
||||
angle = math.atan2((yEnd - yStart), (xEnd - xStart))
|
||||
xLineCentre = (xStart + xEnd) / 2
|
||||
yLineCentre = (yStart + yEnd) / 2
|
||||
xArcCentre = xLineCentre + length * math.cos(angle + dir)
|
||||
yArcCentre = yLineCentre + length * math.sin(angle + dir)
|
||||
code = (f'G{arcType} X{xEnd:.6f} Y{yEnd:.6f} I{xArcCentre - xStart:.6f} J{yArcCentre - yStart:.6f}\n')
|
||||
return False, xEnd, yEnd, code
|
||||
except Exception as e:
|
||||
msg = _('SYSTEM ERROR')
|
||||
error = f'{msg}:\n\n{e}'
|
||||
return True, e
|
||||
|
||||
|
||||
def do_arc_by_angle_radius(Conv, xStart, yStart, length, angle, radius, arcType):
|
||||
error = ''
|
||||
msg1 = _('entry is invalid')
|
||||
valid, xStart = Conv.conv_is_float(xStart)
|
||||
if not valid and xStart:
|
||||
msg0 = _('X START')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, yStart = Conv.conv_is_float(yStart)
|
||||
if not valid and yStart:
|
||||
msg0 = _('Y START')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, length = Conv.conv_is_float(length)
|
||||
if not valid and length:
|
||||
msg0 = _('LENGTH')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, angle = Conv.conv_is_float(angle)
|
||||
if not valid and angle:
|
||||
msg0 = _('ANGLE')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
valid, radius = Conv.conv_is_float(radius)
|
||||
if not valid and radius:
|
||||
msg0 = _('RADIUS')
|
||||
error += f'{msg0} {msg1}\n\n'
|
||||
if error:
|
||||
return True, error
|
||||
if radius == 0:
|
||||
msg = _('RADIUS cannot be zero')
|
||||
error += f'{msg}\n\n'
|
||||
if length == 0:
|
||||
msg = _('LENGTH cannot be zero')
|
||||
error += f'{msg}\n\n'
|
||||
if error:
|
||||
return True, error
|
||||
ang = math.radians(angle)
|
||||
xEnd = xStart + (length * math.cos(ang))
|
||||
yEnd = yStart + (length * math.sin(ang))
|
||||
result = do_arc_2_points_radius(Conv, xStart, yStart, xEnd, yEnd, radius, arcType)
|
||||
return result
|
||||
|
||||
|
||||
def first_segment(fTmp, fNgc, fNgcBkp, preAmble, xStart, yStart, matNumber, matName):
|
||||
with open(fTmp, 'w') as outTmp:
|
||||
with open(fNgc, 'w') as outNgc:
|
||||
with open(fNgcBkp, 'r') as inWiz:
|
||||
for line in inWiz:
|
||||
line = line.strip()
|
||||
if line and line[0] not in ';':
|
||||
if '(new conversational file)' in line:
|
||||
if('\\n') in preAmble:
|
||||
outNgc.write('(preamble)\n')
|
||||
for l in preAmble.split('\\n'):
|
||||
outNgc.write(f'{l}\n')
|
||||
else:
|
||||
outNgc.write(f'\n{preAmble} (preamble)\n')
|
||||
break
|
||||
elif '(postamble)' in line:
|
||||
break
|
||||
elif 'M2' in line.upper() or 'M02' in line.upper() or 'M30' in line.upper():
|
||||
continue
|
||||
outNgc.write(f"{line}\n")
|
||||
outTmp.write('\n(conversational line/arc)\n')
|
||||
outTmp.write(f';using material #{matNumber}: {matName}\n')
|
||||
outTmp.write(f'M190 P{matNumber}\n')
|
||||
outTmp.write('M66 P3 L3 Q1\n')
|
||||
outTmp.write('F#<_hal[plasmac.cut-feed-rate]>\n')
|
||||
outTmp.write(f'G00 X{xStart:.6f} Y{yStart:.6f}\n')
|
||||
outTmp.write('M03 $0 S1\n')
|
||||
|
||||
|
||||
def next_segment(fTmp, fNgc):
|
||||
with open(fTmp, 'w') as outTmp:
|
||||
with open(fNgc, 'r') as inNgc:
|
||||
while(1):
|
||||
line = inNgc.readline()
|
||||
if not line or 'M05 $0' in line:
|
||||
break
|
||||
else:
|
||||
outTmp.write(line)
|
||||
open(fNgc, 'w')
|
||||
|
||||
|
||||
def last_segment(fTmp, fNgc, code, postAmble):
|
||||
with open(fTmp, 'a') as outTmp:
|
||||
outTmp.write(code)
|
||||
outTmp.write('M05 $0\n')
|
||||
with open(fNgc, 'a') as outNgc:
|
||||
with open(fTmp, 'r') as inTmp:
|
||||
for line in inTmp:
|
||||
outNgc.write(line)
|
||||
if('\\n') in postAmble:
|
||||
outNgc.write('\n(postamble)\n')
|
||||
for l in postAmble.split('\\n'):
|
||||
outNgc.write(f'{l}\n')
|
||||
else:
|
||||
outNgc.write(f'\n{postAmble} (postamble)\n')
|
||||
outNgc.write('M02\n')
|
||||
Reference in New Issue
Block a user