From e1dab238a7540282908be478ee83bba6925a5726 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Thu, 2 Jul 2020 17:15:13 +0300 Subject: [PATCH] - fixed importing DXF file as Gerber method such that now the resulting Gerber object is correctly created having the geometry attributes like self.apertures and self.follow_geometry --- CHANGELOG.md | 1 + appParsers/ParseGerber.py | 74 +++++++++++++++++++++++++++----- app_Main.py | 11 +++-- camlib.py | 13 ++---- tclCommands/TclCommandOpenDXF.py | 8 +++- 5 files changed, 81 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b8cf598..ff534025 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ CHANGELOG for FlatCAM beta 2.07.2020 - trying to optimize the resulting geometry in DXF import (and in SVG import) by merging contiguous lines; reduced the lines to about one third of the original +- fixed importing DXF file as Gerber method such that now the resulting Gerber object is correctly created having the geometry attributes like self.apertures and self.follow_geometry 30.06.2020 diff --git a/appParsers/ParseGerber.py b/appParsers/ParseGerber.py index a2d3a20b..f002c745 100644 --- a/appParsers/ParseGerber.py +++ b/appParsers/ParseGerber.py @@ -2,20 +2,22 @@ from PyQt5 import QtWidgets from camlib import Geometry, arc, arc_angle, ApertureMacro, grace import numpy as np -import re -import logging +# import re +# import logging import traceback from copy import deepcopy -import sys +# import sys -from shapely.ops import cascaded_union -from shapely.affinity import scale, translate +from shapely.ops import unary_union, linemerge +# from shapely.affinity import scale, translate import shapely.affinity as affinity -from shapely.geometry import box as shply_box, Polygon, LineString, Point, MultiPolygon +from shapely.geometry import box as shply_box from lxml import etree as ET +import ezdxf + +from appParsers.ParseDXF import * from appParsers.ParseSVG import svgparselength, getsvggeo -import appTranslation as fcTranslate import gettext import builtins @@ -502,10 +504,10 @@ class Gerber(Geometry): if buff_length > 0: if current_polarity == 'D': - self.solid_geometry = self.solid_geometry.union(cascaded_union(poly_buffer)) + self.solid_geometry = self.solid_geometry.union(unary_union(poly_buffer)) else: - self.solid_geometry = self.solid_geometry.difference(cascaded_union(poly_buffer)) + self.solid_geometry = self.solid_geometry.difference(unary_union(poly_buffer)) # follow_buffer = [] poly_buffer = [] @@ -1497,7 +1499,7 @@ class Gerber(Geometry): else: log.debug("Union by union()...") - new_poly = cascaded_union(poly_buffer) + new_poly = unary_union(poly_buffer) new_poly = new_poly.buffer(0, int(self.steps_per_circle / 4)) log.warning("Union done.") @@ -1601,7 +1603,7 @@ class Gerber(Geometry): p2 = Point(loc[0], loc[1] - 0.5 * (height - width)) c1 = p1.buffer(width * 0.5, int(steps_per_circle / 4)) c2 = p2.buffer(width * 0.5, int(steps_per_circle / 4)) - return cascaded_union([c1, c2]).convex_hull + return unary_union([c1, c2]).convex_hull if aperture['type'] == 'P': # Regular polygon loc = location.coords[0] @@ -1836,6 +1838,56 @@ class Gerber(Geometry): new_el['follow'] = pol.exterior self.apertures['0']['geometry'].append(new_el) + def import_dxf_as_gerber(self, filename, units='MM'): + """ + Imports shapes from an DXF file into the Gerberobject geometry. + + :param filename: Path to the DXF file. + :type filename: str + :param units: Application units + :return: None + """ + + log.debug("Parsing DXF file geometry into a Gerber object geometry.") + # Parse into list of shapely objects + dxf = ezdxf.readfile(filename) + geos = getdxfgeo(dxf) + # trying to optimize the resulting geometry by merging contiguous lines + geos = linemerge(geos) + + # Add to object + if self.solid_geometry is None: + self.solid_geometry = [] + + if type(self.solid_geometry) is list: + if type(geos) is list: + self.solid_geometry += geos + else: + self.solid_geometry.append(geos) + else: # It's shapely geometry + self.solid_geometry = [self.solid_geometry, geos] + + # flatten the self.solid_geometry list for import_dxf() to import DXF as Gerber + flat_geo = list(self.flatten_list(self.solid_geometry)) + if flat_geo: + self.solid_geometry = unary_union(flat_geo) + self.follow_geometry = self.solid_geometry + else: + return "fail" + + # create the self.apertures data structure + if '0' not in self.apertures: + self.apertures['0'] = {} + self.apertures['0']['type'] = 'REG' + self.apertures['0']['size'] = 0.0 + self.apertures['0']['geometry'] = [] + + for pol in flat_geo: + new_el = {} + new_el['solid'] = pol + new_el['follow'] = pol + self.apertures['0']['geometry'].append(deepcopy(new_el)) + def scale(self, xfactor, yfactor=None, point=None): """ Scales the objects' geometry on the XY plane by a given factor. diff --git a/app_Main.py b/app_Main.py index a42add60..80244e58 100644 --- a/app_Main.py +++ b/app_Main.py @@ -8617,7 +8617,7 @@ class App(QtCore.QObject): :param plot: If True then the resulting object will be plotted on canvas :return: """ - self.defaults.report_usage("import_dxf()") + log.debug(" ********* Importing SVG as: %s ********* " % geo_type.capitalize()) obj_type = "" if geo_type is None or geo_type == "geometry": @@ -8632,8 +8632,13 @@ class App(QtCore.QObject): units = self.defaults['units'].upper() def obj_init(geo_obj, app_obj): - geo_obj.import_dxf(filename, obj_type, units=units) - geo_obj.multigeo = False + if obj_type == "geometry": + geo_obj.import_dxf_as_geo(filename, units=units) + elif obj_type == "gerber": + geo_obj.import_dxf_as_gerber(filename, units=units) + else: + return "fail" + geo_obj.multigeo = True with self.proc_container.new(_("Importing DXF")): diff --git a/camlib.py b/camlib.py index aa4d314a..e366c45f 100644 --- a/camlib.py +++ b/camlib.py @@ -22,7 +22,7 @@ from rtree import index as rtindex from lxml import etree as ET # See: http://toblerity.org/shapely/manual.html -from shapely.geometry import Polygon, LineString, Point, LinearRing, MultiLineString, MultiPoint, MultiPolygon +from shapely.geometry import Polygon, Point, LinearRing from shapely.geometry import box as shply_box from shapely.ops import cascaded_union, unary_union, substring, linemerge @@ -1087,16 +1087,16 @@ class Geometry(object): if geos_text_f: self.solid_geometry = self.solid_geometry + geos_text_f - def import_dxf(self, filename, object_type=None, units='MM'): + def import_dxf_as_geo(self, filename, units='MM'): """ Imports shapes from an DXF file into the object's geometry. :param filename: Path to the DXF file. :type filename: str - :param object_type: :param units: Application units :return: None """ + log.debug("Parsing DXF file geometry into a Geometry object solid geometry.") # Parse into list of shapely objects dxf = ezdxf.readfile(filename) @@ -1116,13 +1116,6 @@ class Geometry(object): else: # It's shapely geometry self.solid_geometry = [self.solid_geometry, geos] - # flatten the self.solid_geometry list for import_dxf() to import DXF as Gerber - self.solid_geometry = list(self.flatten_list(self.solid_geometry)) - if self.solid_geometry is not None: - self.solid_geometry = cascaded_union(self.solid_geometry) - else: - return - # commented until this function is ready # geos_text = getdxftext(dxf, object_type, units=units) # if geos_text is not None: diff --git a/tclCommands/TclCommandOpenDXF.py b/tclCommands/TclCommandOpenDXF.py index 87ab0639..fe2ad7ef 100644 --- a/tclCommands/TclCommandOpenDXF.py +++ b/tclCommands/TclCommandOpenDXF.py @@ -54,8 +54,12 @@ class TclCommandOpenDXF(TclCommandSignaled): # if geo_obj.kind != 'geometry' and geo_obj.kind != 'gerber': # self.raise_tcl_error('Expected Geometry or Gerber, got %s %s.' % (outname, type(geo_obj))) - - geo_obj.import_dxf(filename, obj_type, units=units) + if obj_type == "geometry": + geo_obj.import_dxf_as_geo(filename, units=units) + elif obj_type == "gerber": + geo_obj.import_dxf_as_gerber(filename, units=units) + else: + return "fail" filename = args['filename']