2019-12-11 12:32:01 +00:00
|
|
|
# ############################################################
|
|
|
|
# FlatCAM: 2D Post-processing for Manufacturing #
|
|
|
|
# http://flatcam.org #
|
2019-12-12 19:29:38 +00:00
|
|
|
# File Author: Marius Adrian Stanciu (c) #
|
2019-12-13 13:54:26 +00:00
|
|
|
# Date: 12/12/2019 #
|
2019-12-11 12:32:01 +00:00
|
|
|
# MIT Licence #
|
|
|
|
# ############################################################
|
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
from camlib import arc, three_point_circle
|
2019-12-11 12:32:01 +00:00
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
import re
|
|
|
|
import logging
|
|
|
|
import traceback
|
|
|
|
from copy import deepcopy
|
|
|
|
import sys
|
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
from shapely.ops import unary_union
|
|
|
|
from shapely.geometry import LineString, Point
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2020-04-27 07:03:22 +00:00
|
|
|
from FlatCAMCommon import GracefulException as grace
|
2019-12-11 12:32:01 +00:00
|
|
|
import FlatCAMTranslation as fcTranslate
|
|
|
|
import gettext
|
|
|
|
import builtins
|
|
|
|
|
|
|
|
if '_' not in builtins.__dict__:
|
|
|
|
_ = gettext.gettext
|
|
|
|
|
|
|
|
log = logging.getLogger('base')
|
|
|
|
|
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
class HPGL2:
|
2019-12-11 12:32:01 +00:00
|
|
|
"""
|
|
|
|
HPGL2 parsing.
|
|
|
|
"""
|
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
def __init__(self, app):
|
2019-12-11 12:32:01 +00:00
|
|
|
"""
|
2019-12-13 13:54:26 +00:00
|
|
|
The constructor takes FlatCAMApp.App as parameter.
|
2019-12-11 12:32:01 +00:00
|
|
|
|
|
|
|
"""
|
2019-12-13 13:54:26 +00:00
|
|
|
self.app = app
|
2019-12-11 12:32:01 +00:00
|
|
|
|
|
|
|
# How to approximate a circle with lines.
|
2019-12-13 13:54:26 +00:00
|
|
|
self.steps_per_circle = int(self.app.defaults["geometry_circle_steps"])
|
2019-12-11 12:32:01 +00:00
|
|
|
self.decimals = self.app.decimals
|
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
# store the file units here
|
2019-12-12 19:29:38 +00:00
|
|
|
self.units = 'MM'
|
|
|
|
|
|
|
|
# storage for the tools
|
2020-02-29 22:52:24 +00:00
|
|
|
self.tools = {}
|
2019-12-12 19:29:38 +00:00
|
|
|
|
2020-02-29 22:52:24 +00:00
|
|
|
self.default_data = {}
|
2019-12-12 19:29:38 +00:00
|
|
|
self.default_data.update({
|
|
|
|
"name": '_ncc',
|
|
|
|
"plot": self.app.defaults["geometry_plot"],
|
|
|
|
"cutz": self.app.defaults["geometry_cutz"],
|
|
|
|
"vtipdia": self.app.defaults["geometry_vtipdia"],
|
|
|
|
"vtipangle": self.app.defaults["geometry_vtipangle"],
|
|
|
|
"travelz": self.app.defaults["geometry_travelz"],
|
|
|
|
"feedrate": self.app.defaults["geometry_feedrate"],
|
|
|
|
"feedrate_z": self.app.defaults["geometry_feedrate_z"],
|
|
|
|
"feedrate_rapid": self.app.defaults["geometry_feedrate_rapid"],
|
|
|
|
"dwell": self.app.defaults["geometry_dwell"],
|
|
|
|
"dwelltime": self.app.defaults["geometry_dwelltime"],
|
|
|
|
"multidepth": self.app.defaults["geometry_multidepth"],
|
|
|
|
"ppname_g": self.app.defaults["geometry_ppname_g"],
|
|
|
|
"depthperpass": self.app.defaults["geometry_depthperpass"],
|
|
|
|
"extracut": self.app.defaults["geometry_extracut"],
|
|
|
|
"extracut_length": self.app.defaults["geometry_extracut_length"],
|
|
|
|
"toolchange": self.app.defaults["geometry_toolchange"],
|
|
|
|
"toolchangez": self.app.defaults["geometry_toolchangez"],
|
|
|
|
"endz": self.app.defaults["geometry_endz"],
|
2020-02-26 02:43:54 +00:00
|
|
|
"endxy": self.app.defaults["geometry_endxy"],
|
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
|
|
|
|
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
|
|
|
|
"startz": self.app.defaults["geometry_startz"],
|
|
|
|
|
|
|
|
"tooldia": self.app.defaults["tools_painttooldia"],
|
|
|
|
"paintmargin": self.app.defaults["tools_paintmargin"],
|
|
|
|
"paintmethod": self.app.defaults["tools_paintmethod"],
|
|
|
|
"selectmethod": self.app.defaults["tools_selectmethod"],
|
|
|
|
"pathconnect": self.app.defaults["tools_pathconnect"],
|
|
|
|
"paintcontour": self.app.defaults["tools_paintcontour"],
|
|
|
|
"paintoverlap": self.app.defaults["tools_paintoverlap"],
|
|
|
|
|
|
|
|
"nccoverlap": self.app.defaults["tools_nccoverlap"],
|
|
|
|
"nccmargin": self.app.defaults["tools_nccmargin"],
|
|
|
|
"nccmethod": self.app.defaults["tools_nccmethod"],
|
|
|
|
"nccconnect": self.app.defaults["tools_nccconnect"],
|
|
|
|
"ncccontour": self.app.defaults["tools_ncccontour"],
|
|
|
|
"nccrest": self.app.defaults["tools_nccrest"]
|
|
|
|
})
|
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
# will store the geometry here for compatibility reason
|
2019-12-11 12:32:01 +00:00
|
|
|
self.solid_geometry = None
|
|
|
|
|
|
|
|
self.source_file = ''
|
|
|
|
|
|
|
|
# ### Parser patterns ## ##
|
|
|
|
|
|
|
|
# comment
|
|
|
|
self.comment_re = re.compile(r"^CO\s*[\"']([a-zA-Z0-9\s]*)[\"'];?$")
|
2019-12-12 19:29:38 +00:00
|
|
|
|
2019-12-11 12:32:01 +00:00
|
|
|
# select pen
|
|
|
|
self.sp_re = re.compile(r'SP(\d);?$')
|
2019-12-13 13:54:26 +00:00
|
|
|
# pen position
|
|
|
|
self.pen_re = re.compile(r"^(P[U|D]);?$")
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
# Initialize
|
|
|
|
self.initialize_re = re.compile(r'^(IN);?$')
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
# Absolute linear interpolation
|
2019-12-16 19:20:08 +00:00
|
|
|
self.abs_move_re = re.compile(r"^PA\s*(-?\d+\.?\d*),?\s*(-?\d+\.?\d*)*;?$")
|
2019-12-13 13:54:26 +00:00
|
|
|
# Relative linear interpolation
|
2019-12-16 19:20:08 +00:00
|
|
|
self.rel_move_re = re.compile(r"^PR\s*(-?\d+\.?\d*),?\s*(-?\d+\.?\d*)*;?$")
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
# Circular interpolation with radius
|
|
|
|
self.circ_re = re.compile(r"^CI\s*(\+?\d+\.?\d+?)?\s*;?\s*$")
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
# Arc interpolation with radius
|
|
|
|
self.arc_re = re.compile(r"^AA\s*([+-]?\d+),?\s*([+-]?\d+),?\s*([+-]?\d+);?$")
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
# Arc interpolation with 3 points
|
|
|
|
self.arc_3pt_re = re.compile(r"^AT\s*([+-]?\d+),?\s*([+-]?\d+),?\s*([+-]?\d+),?\s*([+-]?\d+);?$")
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
self.init_done = None
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
def parse_file(self, filename):
|
2019-12-11 12:32:01 +00:00
|
|
|
"""
|
2019-12-13 13:54:26 +00:00
|
|
|
Creates a list of lines from the HPGL2 file and send it to the main parser.
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
:param filename: HPGL2 file to parse.
|
2019-12-11 12:32:01 +00:00
|
|
|
:type filename: str
|
|
|
|
:return: None
|
|
|
|
"""
|
|
|
|
|
|
|
|
with open(filename, 'r') as gfile:
|
2019-12-13 13:54:26 +00:00
|
|
|
glines = [line.rstrip('\n') for line in gfile]
|
|
|
|
self.parse_lines(glines=glines)
|
2019-12-11 12:32:01 +00:00
|
|
|
|
|
|
|
def parse_lines(self, glines):
|
|
|
|
"""
|
2019-12-12 19:29:38 +00:00
|
|
|
Main HPGL2 parser.
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
:param glines: HPGL2 code as list of strings, each element being
|
2019-12-11 12:32:01 +00:00
|
|
|
one line of the source file.
|
|
|
|
:type glines: list
|
|
|
|
:return: None
|
|
|
|
:rtype: None
|
|
|
|
"""
|
|
|
|
|
|
|
|
# Coordinates of the current path, each is [x, y]
|
2020-02-29 22:52:24 +00:00
|
|
|
path = []
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
geo_buffer = []
|
2019-12-11 12:32:01 +00:00
|
|
|
|
|
|
|
# Current coordinates
|
|
|
|
current_x = None
|
|
|
|
current_y = None
|
2019-12-13 13:54:26 +00:00
|
|
|
|
|
|
|
# Found coordinates
|
|
|
|
linear_x = None
|
|
|
|
linear_y = None
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
# store the pen (tool) status
|
|
|
|
pen_status = 'up'
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
# store the current tool here
|
|
|
|
current_tool = None
|
2019-12-11 12:32:01 +00:00
|
|
|
|
|
|
|
# ### Parsing starts here ## ##
|
|
|
|
line_num = 0
|
|
|
|
gline = ""
|
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
self.app.inform.emit('%s %d %s.' % (_("HPGL2 processing. Parsing"), len(glines), _("lines")))
|
2019-12-11 12:32:01 +00:00
|
|
|
try:
|
|
|
|
for gline in glines:
|
|
|
|
if self.app.abort_flag:
|
|
|
|
# graceful abort requested by the user
|
2020-04-27 07:03:22 +00:00
|
|
|
raise grace
|
2019-12-11 12:32:01 +00:00
|
|
|
|
|
|
|
line_num += 1
|
|
|
|
self.source_file += gline + '\n'
|
|
|
|
|
|
|
|
# Cleanup #
|
|
|
|
gline = gline.strip(' \r\n')
|
|
|
|
# log.debug("Line=%3s %s" % (line_num, gline))
|
|
|
|
|
|
|
|
# ###################
|
|
|
|
# Ignored lines #####
|
|
|
|
# Comments #####
|
|
|
|
# ###################
|
2019-12-12 19:29:38 +00:00
|
|
|
match = self.comment_re.search(gline)
|
2019-12-11 12:32:01 +00:00
|
|
|
if match:
|
2019-12-12 19:29:38 +00:00
|
|
|
log.debug(str(match.group(1)))
|
2019-12-11 12:32:01 +00:00
|
|
|
continue
|
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
# search for the initialization
|
|
|
|
match = self.initialize_re.search(gline)
|
2019-12-11 12:32:01 +00:00
|
|
|
if match:
|
2019-12-13 13:54:26 +00:00
|
|
|
self.init_done = True
|
2019-12-11 12:32:01 +00:00
|
|
|
continue
|
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
if self.init_done is True:
|
2019-12-12 19:29:38 +00:00
|
|
|
# tools detection
|
|
|
|
match = self.sp_re.search(gline)
|
|
|
|
if match:
|
|
|
|
tool = match.group(1)
|
2020-02-29 22:52:24 +00:00
|
|
|
# self.tools[tool] = {}
|
2019-12-12 19:29:38 +00:00
|
|
|
self.tools.update({
|
|
|
|
tool: {
|
|
|
|
'tooldia': float('%.*f' %
|
|
|
|
(
|
|
|
|
self.decimals,
|
|
|
|
float(self.app.defaults['geometry_cnctooldia'])
|
|
|
|
)
|
|
|
|
),
|
|
|
|
'offset': 'Path',
|
|
|
|
'offset_value': 0.0,
|
|
|
|
'type': 'Iso',
|
|
|
|
'tool_type': 'C1',
|
|
|
|
'data': deepcopy(self.default_data),
|
|
|
|
'solid_geometry': list()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
if current_tool:
|
|
|
|
if path:
|
|
|
|
geo = LineString(path)
|
|
|
|
self.tools[current_tool]['solid_geometry'].append(geo)
|
|
|
|
geo_buffer.append(geo)
|
|
|
|
path[:] = []
|
|
|
|
|
|
|
|
current_tool = tool
|
2019-12-11 12:32:01 +00:00
|
|
|
continue
|
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
# pen status detection
|
|
|
|
match = self.pen_re.search(gline)
|
|
|
|
if match:
|
|
|
|
pen_status = {'PU': 'up', 'PD': 'down'}[match.group(1)]
|
2019-12-11 12:32:01 +00:00
|
|
|
continue
|
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
# Linear interpolation
|
2019-12-12 19:29:38 +00:00
|
|
|
match = self.abs_move_re.search(gline)
|
|
|
|
if match:
|
|
|
|
# Parse coordinates
|
|
|
|
if match.group(1) is not None:
|
|
|
|
linear_x = parse_number(match.group(1))
|
|
|
|
current_x = linear_x
|
2019-12-11 12:32:01 +00:00
|
|
|
else:
|
2019-12-12 19:29:38 +00:00
|
|
|
linear_x = current_x
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
if match.group(2) is not None:
|
|
|
|
linear_y = parse_number(match.group(2))
|
|
|
|
current_y = linear_y
|
|
|
|
else:
|
|
|
|
linear_y = current_y
|
|
|
|
|
|
|
|
# Pen down: add segment
|
|
|
|
if pen_status == 'down':
|
|
|
|
# if linear_x or linear_y are None, ignore those
|
|
|
|
if current_x is not None and current_y is not None:
|
|
|
|
# only add the point if it's a new one otherwise skip it (harder to process)
|
|
|
|
if path[-1] != [current_x, current_y]:
|
|
|
|
path.append([current_x, current_y])
|
|
|
|
else:
|
|
|
|
self.app.inform.emit('[WARNING] %s: %s' %
|
|
|
|
(_("Coordinates missing, line ignored"), str(gline)))
|
|
|
|
|
|
|
|
elif pen_status == 'up':
|
|
|
|
if len(path) > 1:
|
|
|
|
geo = LineString(path)
|
|
|
|
self.tools[current_tool]['solid_geometry'].append(geo)
|
|
|
|
geo_buffer.append(geo)
|
2019-12-13 04:53:13 +00:00
|
|
|
path[:] = []
|
2019-12-12 19:29:38 +00:00
|
|
|
|
|
|
|
# if linear_x or linear_y are None, ignore those
|
|
|
|
if linear_x is not None and linear_y is not None:
|
|
|
|
path = [[linear_x, linear_y]] # Start new path
|
|
|
|
else:
|
|
|
|
self.app.inform.emit('[WARNING] %s: %s' %
|
|
|
|
(_("Coordinates missing, line ignored"), str(gline)))
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
# log.debug("Line_number=%3s X=%s Y=%s (%s)" % (line_num, linear_x, linear_y, gline))
|
2019-12-11 12:32:01 +00:00
|
|
|
continue
|
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
# Circular interpolation
|
2019-12-12 19:29:38 +00:00
|
|
|
match = self.circ_re.search(gline)
|
2019-12-13 13:54:26 +00:00
|
|
|
if match:
|
|
|
|
if len(path) > 1:
|
|
|
|
geo = LineString(path)
|
|
|
|
self.tools[current_tool]['solid_geometry'].append(geo)
|
|
|
|
geo_buffer.append(geo)
|
|
|
|
path[:] = []
|
|
|
|
|
|
|
|
# if linear_x or linear_y are None, ignore those
|
|
|
|
if linear_x is not None and linear_y is not None:
|
|
|
|
path = [[linear_x, linear_y]] # Start new path
|
|
|
|
else:
|
|
|
|
self.app.inform.emit('[WARNING] %s: %s' %
|
|
|
|
(_("Coordinates missing, line ignored"), str(gline)))
|
|
|
|
|
|
|
|
if current_x is not None and current_y is not None:
|
2020-04-27 07:03:22 +00:00
|
|
|
radius = float(match.group(1))
|
2019-12-13 13:54:26 +00:00
|
|
|
geo = Point((current_x, current_y)).buffer(radius, int(self.steps_per_circle))
|
|
|
|
geo_line = geo.exterior
|
|
|
|
self.tools[current_tool]['solid_geometry'].append(geo_line)
|
|
|
|
geo_buffer.append(geo_line)
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Arc interpolation with radius
|
|
|
|
match = self.arc_re.search(gline)
|
|
|
|
if match:
|
|
|
|
if len(path) > 1:
|
|
|
|
geo = LineString(path)
|
|
|
|
self.tools[current_tool]['solid_geometry'].append(geo)
|
|
|
|
geo_buffer.append(geo)
|
|
|
|
path[:] = []
|
|
|
|
|
|
|
|
# if linear_x or linear_y are None, ignore those
|
|
|
|
if linear_x is not None and linear_y is not None:
|
|
|
|
path = [[linear_x, linear_y]] # Start new path
|
|
|
|
else:
|
|
|
|
self.app.inform.emit('[WARNING] %s: %s' %
|
|
|
|
(_("Coordinates missing, line ignored"), str(gline)))
|
|
|
|
|
|
|
|
if current_x is not None and current_y is not None:
|
|
|
|
center = [parse_number(match.group(1)), parse_number(match.group(2))]
|
|
|
|
angle = np.deg2rad(float(match.group(3)))
|
|
|
|
p1 = [current_x, current_y]
|
|
|
|
|
|
|
|
arcdir = "ccw" if angle >= 0.0 else "cw"
|
|
|
|
radius = np.sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2)
|
|
|
|
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
|
|
|
stopangle = startangle + angle
|
|
|
|
|
|
|
|
geo = LineString(arc(center, radius, startangle, stopangle, arcdir, self.steps_per_circle))
|
|
|
|
self.tools[current_tool]['solid_geometry'].append(geo)
|
|
|
|
geo_buffer.append(geo)
|
|
|
|
|
|
|
|
line_coords = list(geo.coords)
|
|
|
|
current_x = line_coords[0]
|
|
|
|
current_y = line_coords[1]
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Arc interpolation with 3 points
|
|
|
|
match = self.arc_3pt_re.search(gline)
|
|
|
|
if match:
|
|
|
|
if len(path) > 1:
|
|
|
|
geo = LineString(path)
|
|
|
|
self.tools[current_tool]['solid_geometry'].append(geo)
|
|
|
|
geo_buffer.append(geo)
|
|
|
|
path[:] = []
|
|
|
|
|
|
|
|
# if linear_x or linear_y are None, ignore those
|
|
|
|
if linear_x is not None and linear_y is not None:
|
|
|
|
path = [[linear_x, linear_y]] # Start new path
|
|
|
|
else:
|
|
|
|
self.app.inform.emit('[WARNING] %s: %s' %
|
|
|
|
(_("Coordinates missing, line ignored"), str(gline)))
|
|
|
|
|
|
|
|
if current_x is not None and current_y is not None:
|
|
|
|
p1 = [current_x, current_y]
|
|
|
|
p3 = [parse_number(match.group(1)), parse_number(match.group(2))]
|
|
|
|
p2 = [parse_number(match.group(3)), parse_number(match.group(4))]
|
|
|
|
|
|
|
|
try:
|
|
|
|
center, radius, t = three_point_circle(p1, p2, p3)
|
|
|
|
except TypeError:
|
|
|
|
return
|
|
|
|
|
|
|
|
direction = 'cw' if np.sign(t) > 0 else 'ccw'
|
|
|
|
|
|
|
|
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
|
|
|
stopangle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
|
|
|
|
|
|
|
|
geo = LineString(arc(center, radius, startangle, stopangle,
|
|
|
|
direction, self.steps_per_circle))
|
|
|
|
self.tools[current_tool]['solid_geometry'].append(geo)
|
|
|
|
geo_buffer.append(geo)
|
|
|
|
|
|
|
|
# p2 is the end point for the 3-pt circle
|
|
|
|
current_x = p2[0]
|
|
|
|
current_y = p2[1]
|
|
|
|
continue
|
2019-12-11 12:32:01 +00:00
|
|
|
|
|
|
|
# ## Line did not match any pattern. Warn user.
|
|
|
|
log.warning("Line ignored (%d): %s" % (line_num, gline))
|
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
if not geo_buffer and not self.solid_geometry:
|
2019-12-12 19:29:38 +00:00
|
|
|
log.error("Object is not HPGL2 file or empty. Aborting Object creation.")
|
2019-12-11 12:32:01 +00:00
|
|
|
return 'fail'
|
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
log.warning("Joining %d polygons." % len(geo_buffer))
|
|
|
|
self.app.inform.emit('%s: %d.' % (_("Gerber processing. Joining polygons"), len(geo_buffer)))
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
new_poly = unary_union(geo_buffer)
|
|
|
|
self.solid_geometry = new_poly
|
2019-12-11 12:32:01 +00:00
|
|
|
|
|
|
|
except Exception as err:
|
|
|
|
ex_type, ex, tb = sys.exc_info()
|
|
|
|
traceback.print_tb(tb)
|
2019-12-13 22:04:52 +00:00
|
|
|
print(traceback.format_exc())
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
log.error("HPGL2 PARSING FAILED. Line %d: %s" % (line_num, gline))
|
2019-12-11 12:32:01 +00:00
|
|
|
|
2019-12-12 19:29:38 +00:00
|
|
|
loc = '%s #%d %s: %s\n' % (_("HPGL2 Line"), line_num, _("HPGL2 Line Content"), gline) + repr(err)
|
|
|
|
self.app.inform.emit('[ERROR] %s\n%s:' % (_("HPGL2 Parser ERROR"), loc))
|
2019-12-11 12:32:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
def parse_number(strnumber):
|
|
|
|
"""
|
|
|
|
Parse a single number of HPGL2 coordinates.
|
|
|
|
|
|
|
|
:param strnumber: String containing a number
|
|
|
|
from a coordinate data block, possibly with a leading sign.
|
|
|
|
:type strnumber: str
|
|
|
|
:return: The number in floating point.
|
|
|
|
:rtype: float
|
|
|
|
"""
|
|
|
|
|
2019-12-13 13:54:26 +00:00
|
|
|
return float(strnumber) / 40.0 # in milimeters
|