From 900d992fa3af05f93ac7a4cf717f28598e1a868d Mon Sep 17 00:00:00 2001 From: opiopan Date: Sun, 31 Mar 2019 13:30:15 +0900 Subject: auto detection closed paths in the collection of DXF arc object and line object, then fill these closed path --- gerberex/dxf_path.py | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 gerberex/dxf_path.py (limited to 'gerberex/dxf_path.py') diff --git a/gerberex/dxf_path.py b/gerberex/dxf_path.py new file mode 100644 index 0000000..b066b08 --- /dev/null +++ b/gerberex/dxf_path.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright 2019 Hiroshi Murayama + +from gerber.utils import inch, metric, write_gerber_value +from gerber.cam import FileSettings + +class DxfPath(object): + def __init__(self, statement, error_range=0): + self.statements = [statement] + self.error_range = error_range + + @property + def start(self): + return self.statements[0].start + + @property + def end(self): + return self.statements[-1].end + + @property + def is_closed(self): + from gerberex.dxf import is_equal_point + return len(self.statements) > 1 and \ + is_equal_point(self.start, self.end, self.error_range) + + def is_equal_to(self, target, error_range=0): + from gerberex.dxf import is_equal_point + if not isinstance(target, DxfPath): + return False + if len(self.statements) != len(target.statements): + return False + if is_equal_point(self.start, target.start, error_range) and \ + is_equal_point(self.end, target.end, error_range): + for i in range(0, len(self.statements)): + if not self.statements[i].is_equal_to(target.statements[i], error_range): + return False + return True + elif is_equal_point(self.start, target.end, error_range) and \ + is_equal_point(self.end, target.start, error_range): + for i in range(0, len(self.statements)): + if not self.statements[i].is_equal_to(target.statements[-1 - i], error_range): + return False + return True + return False + + def to_inch(self): + self.error_range = inch(self.error_range) + + def to_metric(self): + self.error_range = metric(self.error_range) + + def reverse(self): + rlist = [] + for statement in reversed(self.statements): + statement.reverse() + rlist.append(statement) + self.statements = rlist + + def merge(self, element, error_range=0): + from gerberex.dxf import is_equal_point + if self.is_closed or element.is_closed: + return False + if not error_range: + error_range = self.error_range + if is_equal_point(self.end, element.start, error_range): + return self._append_at_end(element, error_range) + elif is_equal_point(self.end, element.end, error_range): + element.reverse() + return self._append_at_end(element, error_range) + elif is_equal_point(self.start, element.end, error_range): + return self._insert_on_top(element, error_range) + elif is_equal_point(self.start, element.start, error_range): + element.reverse() + return self._insert_on_top(element, error_range) + else: + return False + + def _append_at_end(self, element, error_range=0): + if isinstance(element, DxfPath): + if self.is_equal_to(element, error_range): + return False + for i in range(0, min(len(self.statements), len(element.statements))): + if not self.statements[-1 - i].is_equal_to(element.statements[i]): + break + for j in range(0, min(len(self.statements), len(element.statements))): + if not self.statements[j].is_equal_to(element.statements[-1 - j]): + break + if i + j >= len(element.statements): + return False + mergee = list(element.statements) + if i > 0: + del mergee[0:i] + del self.statements[-i] + if j > 0: + del mergee[-j] + del self.statements[0:j] + self.statements.extend(mergee) + return True + else: + if self.statements[-1].is_equal_to(element, error_range) or \ + self.statements[0].is_equal_to(element, error_range): + return False + self.statements.appen(element) + return True + + def _insert_on_top(self, element, error_range=0): + if isinstance(element, DxfPath): + if self.is_equal_to(element, error_range): + return False + for i in range(0, min(len(self.statements), len(element.statements))): + if not self.statements[-1 - i].is_equal_to(element.statements[i]): + break + for j in range(0, min(len(self.statements), len(element.statements))): + if not self.statements[j].is_equal_to(element.statements[-1 - j]): + break + if i + j >= len(element.statements): + return False + mergee = list(element.statements) + if i > 0: + del mergee[0:i] + del self.statements[-i] + if j > 0: + del mergee[-j] + del self.statements[0:j] + self.statements[0:0] = mergee + return True + else: + if self.statements[-1].is_equal_to(element, error_range) or \ + self.statements[0].is_equal_to(element, error_range): + return False + self.statements.insert(0, element) + return True + + def to_gerber(self, settings=FileSettings(), pitch=0, width=0): + from gerberex.dxf import DxfArcStatement + if pitch: + return + + x0, y0 = self.statements[0].start + gerber = 'G01*\nX{0}Y{1}D02*\nG75*'.format( + write_gerber_value(x0, settings.format, + settings.zero_suppression), + write_gerber_value(y0, settings.format, + settings.zero_suppression), + ) + + for statement in self.statements: + x0, y0 = statement.start + x1, y1 = statement.end + if isinstance(statement, DxfArcStatement): + xc, yc = statement.center + gerber += '\nG{0}*\nX{1}Y{2}I{3}J{4}D01*'.format( + '03' if statement.end_angle > statement.start_angle else '02', + write_gerber_value(x1, settings.format, + settings.zero_suppression), + write_gerber_value(y1, settings.format, + settings.zero_suppression), + write_gerber_value(xc - x0, settings.format, + settings.zero_suppression), + write_gerber_value(yc - y0, settings.format, + settings.zero_suppression) + ) + else: + gerber += '\nG01*\nX{0}Y{1}D01*'.format( + write_gerber_value(x1, settings.format, + settings.zero_suppression), + write_gerber_value(y1, settings.format, + settings.zero_suppression), + ) + + return gerber + +def generate_closed_paths(statements, error_range=0): + from gerberex.dxf import DxfLineStatement, DxfArcStatement + + paths = [DxfPath(s, error_range) \ + for s in filter(lambda s: isinstance(s, DxfLineStatement) or \ + isinstance(s, DxfArcStatement), statements)] + + prev_paths_num = 0 + while prev_paths_num != len(paths): + working = [] + for i in range(len(paths)): + mergee = paths[i] + for j in range(i + 1, len(paths) - 1): + target = paths[j] + if target.merge(mergee, error_range): + break + else: + working.append(mergee) + prev_paths_num = len(paths) + paths = working + + return list(filter(lambda p: p.is_closed, paths)) + -- cgit From 53816574a986722d7af26c5597248d9c96f31bd3 Mon Sep 17 00:00:00 2001 From: opiopan Date: Sun, 31 Mar 2019 18:16:34 +0900 Subject: fix a minor issue --- gerberex/dxf_path.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'gerberex/dxf_path.py') diff --git a/gerberex/dxf_path.py b/gerberex/dxf_path.py index b066b08..930d8d2 100644 --- a/gerberex/dxf_path.py +++ b/gerberex/dxf_path.py @@ -184,7 +184,7 @@ def generate_closed_paths(statements, error_range=0): working = [] for i in range(len(paths)): mergee = paths[i] - for j in range(i + 1, len(paths) - 1): + for j in range(i + 1, len(paths)): target = paths[j] if target.merge(mergee, error_range): break @@ -192,6 +192,5 @@ def generate_closed_paths(statements, error_range=0): working.append(mergee) prev_paths_num = len(paths) paths = working - return list(filter(lambda p: p.is_closed, paths)) -- cgit From cb420e39e278f7ab6f002600a7698d7be101eb7d Mon Sep 17 00:00:00 2001 From: opiopan Date: Wed, 3 Apr 2019 00:30:00 +0900 Subject: fix a rotaion issue --- gerberex/dxf_path.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'gerberex/dxf_path.py') diff --git a/gerberex/dxf_path.py b/gerberex/dxf_path.py index 930d8d2..2825c58 100644 --- a/gerberex/dxf_path.py +++ b/gerberex/dxf_path.py @@ -5,6 +5,7 @@ from gerber.utils import inch, metric, write_gerber_value from gerber.cam import FileSettings +from gerberex.utility import is_equal_point, is_equal_value class DxfPath(object): def __init__(self, statement, error_range=0): @@ -21,12 +22,10 @@ class DxfPath(object): @property def is_closed(self): - from gerberex.dxf import is_equal_point return len(self.statements) > 1 and \ is_equal_point(self.start, self.end, self.error_range) def is_equal_to(self, target, error_range=0): - from gerberex.dxf import is_equal_point if not isinstance(target, DxfPath): return False if len(self.statements) != len(target.statements): @@ -59,7 +58,6 @@ class DxfPath(object): self.statements = rlist def merge(self, element, error_range=0): - from gerberex.dxf import is_equal_point if self.is_closed or element.is_closed: return False if not error_range: -- cgit From 6ec58842030b0bbe6aa3391456f017d71b74aeaa Mon Sep 17 00:00:00 2001 From: opiopan Date: Wed, 24 Apr 2019 22:55:23 +0900 Subject: fix a genarating closed path issue --- gerberex/dxf_path.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'gerberex/dxf_path.py') diff --git a/gerberex/dxf_path.py b/gerberex/dxf_path.py index 2825c58..ca48d00 100644 --- a/gerberex/dxf_path.py +++ b/gerberex/dxf_path.py @@ -173,9 +173,20 @@ class DxfPath(object): def generate_closed_paths(statements, error_range=0): from gerberex.dxf import DxfLineStatement, DxfArcStatement - paths = [DxfPath(s, error_range) \ - for s in filter(lambda s: isinstance(s, DxfLineStatement) or \ - isinstance(s, DxfArcStatement), statements)] + unique_statements = [] + redundant = 0 + for statement in statements: + for target in unique_statements: + if not isinstance(statement, DxfLineStatement) and \ + not isinstance(statement, DxfArcStatement): + break + if statement.is_equal_to(target, error_range): + redundant += 1 + break + else: + unique_statements.append(statement) + + paths = [DxfPath(s, error_range) for s in unique_statements] prev_paths_num = 0 while prev_paths_num != len(paths): -- cgit From fc3f1a23b87d9c4e51967abb0ed4107daa2be5cf Mon Sep 17 00:00:00 2001 From: Hiroshi Murayama Date: Sat, 28 Sep 2019 17:40:09 +0900 Subject: improve DXF file handling functions: - DM_LINE mode support to generate Excellon routing sequence - DM_MOUSE_BITES mode support to generate mouse bites along all path also, not only line object --- gerberex/dxf_path.py | 174 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 128 insertions(+), 46 deletions(-) (limited to 'gerberex/dxf_path.py') diff --git a/gerberex/dxf_path.py b/gerberex/dxf_path.py index ca48d00..0a92287 100644 --- a/gerberex/dxf_path.py +++ b/gerberex/dxf_path.py @@ -6,10 +6,11 @@ from gerber.utils import inch, metric, write_gerber_value from gerber.cam import FileSettings from gerberex.utility import is_equal_point, is_equal_value +from gerberex.excellon import CoordinateStmtEx class DxfPath(object): - def __init__(self, statement, error_range=0): - self.statements = [statement] + def __init__(self, statements, error_range=0): + self.statements = statements self.error_range = error_range @property @@ -22,8 +23,10 @@ class DxfPath(object): @property def is_closed(self): - return len(self.statements) > 1 and \ - is_equal_point(self.start, self.end, self.error_range) + if len(self.statements) == 1: + return self.statements[0].is_closed + else: + return is_equal_point(self.start, self.end, self.error_range) def is_equal_to(self, target, error_range=0): if not isinstance(target, DxfPath): @@ -43,12 +46,31 @@ class DxfPath(object): return False return True return False + + def contain(self, target, error_range=0): + for statement in self.statements: + if statement.is_equal_to(target, error_range): + return True + else: + return False def to_inch(self): self.error_range = inch(self.error_range) + for statement in self.statements: + statement.to_inch() def to_metric(self): self.error_range = metric(self.error_range) + for statement in self.statements: + statement.to_metric() + + def offset(self, offset_x, offset_y): + for statement in self.statements: + statement.offset(offset_x, offset_y) + + def rotate(self, angle, center=(0, 0)): + for statement in self.statements: + statement.rotate(angle, center) def reverse(self): rlist = [] @@ -133,60 +155,118 @@ class DxfPath(object): def to_gerber(self, settings=FileSettings(), pitch=0, width=0): from gerberex.dxf import DxfArcStatement - if pitch: - return + if pitch == 0: + x0, y0 = self.statements[0].start + gerber = 'G01*\nX{0}Y{1}D02*\nG75*'.format( + write_gerber_value(x0, settings.format, + settings.zero_suppression), + write_gerber_value(y0, settings.format, + settings.zero_suppression), + ) - x0, y0 = self.statements[0].start - gerber = 'G01*\nX{0}Y{1}D02*\nG75*'.format( - write_gerber_value(x0, settings.format, - settings.zero_suppression), - write_gerber_value(y0, settings.format, - settings.zero_suppression), - ) - - for statement in self.statements: - x0, y0 = statement.start - x1, y1 = statement.end - if isinstance(statement, DxfArcStatement): - xc, yc = statement.center - gerber += '\nG{0}*\nX{1}Y{2}I{3}J{4}D01*'.format( - '03' if statement.end_angle > statement.start_angle else '02', - write_gerber_value(x1, settings.format, - settings.zero_suppression), - write_gerber_value(y1, settings.format, - settings.zero_suppression), - write_gerber_value(xc - x0, settings.format, - settings.zero_suppression), - write_gerber_value(yc - y0, settings.format, - settings.zero_suppression) - ) - else: - gerber += '\nG01*\nX{0}Y{1}D01*'.format( - write_gerber_value(x1, settings.format, - settings.zero_suppression), - write_gerber_value(y1, settings.format, + for statement in self.statements: + x0, y0 = statement.start + x1, y1 = statement.end + if isinstance(statement, DxfArcStatement): + xc, yc = statement.center + gerber += '\nG{0}*\nX{1}Y{2}I{3}J{4}D01*'.format( + '03' if statement.end_angle > statement.start_angle else '02', + write_gerber_value(x1, settings.format, + settings.zero_suppression), + write_gerber_value(y1, settings.format, + settings.zero_suppression), + write_gerber_value(xc - x0, settings.format, + settings.zero_suppression), + write_gerber_value(yc - y0, settings.format, + settings.zero_suppression) + ) + else: + gerber += '\nG01*\nX{0}Y{1}D01*'.format( + write_gerber_value(x1, settings.format, + settings.zero_suppression), + write_gerber_value(y1, settings.format, + settings.zero_suppression), + ) + else: + def ploter(x, y): + return 'X{0}Y{1}D03*\n'.format( + write_gerber_value(x, settings.format, settings.zero_suppression), + write_gerber_value(y, settings.format, + settings.zero_suppression), ) + gerber = self._plot_dots(pitch, width, ploter) return gerber -def generate_closed_paths(statements, error_range=0): - from gerberex.dxf import DxfLineStatement, DxfArcStatement + def to_excellon(self, settings=FileSettings(), pitch=0, width=0): + from gerberex.dxf import DxfArcStatement + if pitch == 0: + x, y = self.statements[0].start + excellon = 'G00{0}\nM15\n'.format( + CoordinateStmtEx(x=x, y=y).to_excellon(settings)) + + for statement in self.statements: + x, y = statement.end + if isinstance(statement, DxfArcStatement): + r = statement.radius + excellon += '{0}{1}\n'.format( + 'G03' if statement.end_angle > statement.start_angle else 'G02', + CoordinateStmtEx(x=x, y=y, radius=r).to_excellon(settings)) + else: + excellon += 'G01{0}\n'.format( + CoordinateStmtEx(x=x, y=y).to_excellon(settings)) + + excellon += 'M16\nG05\n' + else: + def ploter(x, y): + return CoordinateStmtEx(x=x, y=y).to_excellon(settings) + '\n' + excellon = self._plot_dots(pitch, width, ploter) + + return excellon + + def _plot_dots(self, pitch, width, ploter): + out = '' + offset = 0 + for idx in range(0, len(self.statements)): + statement = self.statements[idx] + if offset < 0: + offset += pitch + for dot, offset in statement.dots(pitch, width, offset): + if dot is None: + break + if offset > 0 and (statement.is_closed or idx != len(self.statements) - 1): + break + #if idx == len(self.statements) - 1 and statement.is_closed and offset > -pitch: + # break + out += ploter(dot[0], dot[1]) + return out + + +def generate_paths(statements, error_range=0): + from gerberex.dxf import DxfPolylineStatement + + paths = [] + for statement in filter(lambda s: isinstance(s, DxfPolylineStatement), statements): + units = [unit for unit in statement.disassemble()] + paths.append(DxfPath(units, error_range)) unique_statements = [] redundant = 0 - for statement in statements: - for target in unique_statements: - if not isinstance(statement, DxfLineStatement) and \ - not isinstance(statement, DxfArcStatement): - break - if statement.is_equal_to(target, error_range): + for statement in filter(lambda s: not isinstance(s, DxfPolylineStatement), statements): + for path in paths: + if path.contain(statement): redundant += 1 break else: - unique_statements.append(statement) + for target in unique_statements: + if statement.is_equal_to(target, error_range): + redundant += 1 + break + else: + unique_statements.append(statement) - paths = [DxfPath(s, error_range) for s in unique_statements] + paths.extend([DxfPath([s], error_range) for s in unique_statements]) prev_paths_num = 0 while prev_paths_num != len(paths): @@ -201,5 +281,7 @@ def generate_closed_paths(statements, error_range=0): working.append(mergee) prev_paths_num = len(paths) paths = working - return list(filter(lambda p: p.is_closed, paths)) + closed_path = list(filter(lambda p: p.is_closed, paths)) + open_path = list(filter(lambda p: not p.is_closed, paths)) + return (closed_path, open_path) -- cgit From 48b35377b1cce897a70d1d037b3e73b616af9be7 Mon Sep 17 00:00:00 2001 From: Hiroshi Murayama Date: Sat, 28 Sep 2019 20:42:11 +0900 Subject: minor refactoring --- gerberex/dxf_path.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'gerberex/dxf_path.py') diff --git a/gerberex/dxf_path.py b/gerberex/dxf_path.py index 0a92287..1307411 100644 --- a/gerberex/dxf_path.py +++ b/gerberex/dxf_path.py @@ -202,20 +202,22 @@ class DxfPath(object): def to_excellon(self, settings=FileSettings(), pitch=0, width=0): from gerberex.dxf import DxfArcStatement if pitch == 0: - x, y = self.statements[0].start + x0, y0 = self.statements[0].start excellon = 'G00{0}\nM15\n'.format( - CoordinateStmtEx(x=x, y=y).to_excellon(settings)) + CoordinateStmtEx(x=x0, y=y0).to_excellon(settings)) for statement in self.statements: - x, y = statement.end + x0, y0 = statement.start + x1, y1 = statement.end if isinstance(statement, DxfArcStatement): - r = statement.radius + i = statement.center[0] - x0 + j = statement.center[1] - y0 excellon += '{0}{1}\n'.format( 'G03' if statement.end_angle > statement.start_angle else 'G02', - CoordinateStmtEx(x=x, y=y, radius=r).to_excellon(settings)) + CoordinateStmtEx(x=x1, y=y1, i=i, j=j).to_excellon(settings)) else: excellon += 'G01{0}\n'.format( - CoordinateStmtEx(x=x, y=y).to_excellon(settings)) + CoordinateStmtEx(x=x1, y=y1).to_excellon(settings)) excellon += 'M16\nG05\n' else: -- cgit From 244fcaa5346f4fad819cc2b72857cfb2c472944a Mon Sep 17 00:00:00 2001 From: Hiroshi Murayama Date: Sat, 28 Dec 2019 23:45:33 +0900 Subject: add a function that generate filled gerberdata with representing internal shape by fliping polarity --- gerberex/dxf_path.py | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) (limited to 'gerberex/dxf_path.py') diff --git a/gerberex/dxf_path.py b/gerberex/dxf_path.py index 1307411..bb620ff 100644 --- a/gerberex/dxf_path.py +++ b/gerberex/dxf_path.py @@ -5,13 +5,17 @@ from gerber.utils import inch, metric, write_gerber_value from gerber.cam import FileSettings -from gerberex.utility import is_equal_point, is_equal_value +from gerberex.utility import is_equal_point, is_equal_value, normalize_vec2d, dot_vec2d from gerberex.excellon import CoordinateStmtEx class DxfPath(object): def __init__(self, statements, error_range=0): self.statements = statements self.error_range = error_range + self.bounding_box = statements[0].bounding_box + self.containers = [] + for statement in statements[1:]: + self._merge_bounding_box(statement.bounding_box) @property def start(self): @@ -116,12 +120,15 @@ class DxfPath(object): if j > 0: del mergee[-j] del self.statements[0:j] + for statement in mergee: + self._merge_bounding_box(statement.bounding_box) self.statements.extend(mergee) return True else: if self.statements[-1].is_equal_to(element, error_range) or \ self.statements[0].is_equal_to(element, error_range): return False + self._merge_bounding_box(element.bounding_box) self.statements.appen(element) return True @@ -153,6 +160,21 @@ class DxfPath(object): self.statements.insert(0, element) return True + def _merge_bounding_box(self, box): + self.bounding_box = (min(self.bounding_box[0], box[0]), + min(self.bounding_box[1], box[1]), + max(self.bounding_box[2], box[2]), + max(self.bounding_box[3], box[3])) + + def may_be_in_collision(self, path): + if self.bounding_box[0] >= path.bounding_box[2] or \ + self.bounding_box[1] >= path.bounding_box[3] or \ + self.bounding_box[2] <= path.bounding_box[0] or \ + self.bounding_box[3] <= path.bounding_box[1]: + return False + else: + return True + def to_gerber(self, settings=FileSettings(), pitch=0, width=0): from gerberex.dxf import DxfArcStatement if pitch == 0: @@ -244,7 +266,61 @@ class DxfPath(object): out += ploter(dot[0], dot[1]) return out + def intersections_with_halfline(self, point_from, point_to, error_range=0): + def calculator(statement): + return statement.intersections_with_halfline(point_from, point_to, error_range) + def validator(pt, statement, idx): + if is_equal_point(pt, statement.end, error_range) and \ + not self._judge_cross(point_from, point_to, idx, error_range): + return False + return True + return self._collect_intersections(calculator, validator, error_range) + + def intersections_with_arc(self, center, radius, angle_regions, error_range=0): + def calculator(statement): + return statement.intersections_with_arc(center, radius, angle_regions, error_range) + return self._collect_intersections(calculator, None, error_range) + def _collect_intersections(self, calculator, validator, error_range): + allpts = [] + last = allpts + for i in range(0, len(self.statements)): + statement = self.statements[i] + cur = calculator(statement) + if cur: + for pt in cur: + for dest in allpts: + if is_equal_point(pt, dest, error_range): + break + else: + if validator is not None and not validator(pt, statement, i): + continue + allpts.append(pt) + last = cur + return allpts + + def _judge_cross(self, from_pt, to_pt, index, error_range): + standard = normalize_vec2d((to_pt[0] - from_pt[0], to_pt[1] - from_pt[1])) + normal = (standard[1], standard[0]) + def statements(): + for i in range(index, len(self.statements)): + yield self.statements[i] + for i in range(0, index): + yield self.statements[i] + dot_standard = None + for statement in statements(): + tstart = statement.start + tend = statement.end + target = normalize_vec2d((tend[0] - tstart[0], tend[1] - tstart[1])) + dot= dot_vec2d(normal, target) + if dot_standard is None: + dot_standard = dot + continue + if is_equal_point(standard, target, error_range): + continue + return (dot_standard > 0 and dot > 0) or (dot_standard < 0 and dot < 0) + raise Exception('inconsistensy is detected while cross judgement between paths') + def generate_paths(statements, error_range=0): from gerberex.dxf import DxfPolylineStatement @@ -287,3 +363,50 @@ def generate_paths(statements, error_range=0): closed_path = list(filter(lambda p: p.is_closed, paths)) open_path = list(filter(lambda p: not p.is_closed, paths)) return (closed_path, open_path) + +def judge_containment(path1, path2, error_range=0): + from gerberex.dxf import DxfArcStatement, DxfLineStatement + + nocontainment = (None, None) + if not path1.may_be_in_collision(path2): + return nocontainment + + def is_in_line_segment(point_from, point_to, point): + dx = point_to[0] - point_from[0] + ratio = (point[0] - point_from[0]) / dx if dx != 0 else \ + (point[1] - point_from[1]) / (point_to[1] - point_from[1]) + return ratio >= 0 and ratio <= 1 + + def contain_in_path(statement, path): + if isinstance(statement, DxfLineStatement): + segment = (statement.start, statement.end) + elif isinstance(statement, DxfArcStatement): + if statement.start == statement.end: + segment = (statement.start, statement.center) + else: + segment = (statement.start, statement.end) + else: + raise Exception('invalid dxf statement type') + pts = path.intersections_with_halfline(segment[0], segment[1], error_range) + if len(pts) % 2 == 0: + return False + for pt in pts: + if is_in_line_segment(segment[0], segment[1], pt): + return False + if isinstance(statement, DxfArcStatement): + pts = path.intersections_with_arc( + statement.center, statement.radius, statement.angle_regions, error_range) + if len(pts) > 0: + return False + return True + + if contain_in_path(path1.statements[0], path2): + containment = [path1, path2] + elif contain_in_path(path2.statements[0], path1): + containment = [path2, path1] + else: + return nocontainment + for i in range(1, len(containment[0].statements)): + if not contain_in_path(containment[0].statements[i], containment[1]): + return nocontainment + return containment -- cgit From ca23fbd9534ab3cba3fd7b032816766c1150ebf9 Mon Sep 17 00:00:00 2001 From: Hiroshi Murayama Date: Mon, 30 Dec 2019 17:51:48 +0900 Subject: fix bugs that fail judgement of path's containment --- gerberex/dxf_path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gerberex/dxf_path.py') diff --git a/gerberex/dxf_path.py b/gerberex/dxf_path.py index bb620ff..960b054 100644 --- a/gerberex/dxf_path.py +++ b/gerberex/dxf_path.py @@ -301,7 +301,7 @@ class DxfPath(object): def _judge_cross(self, from_pt, to_pt, index, error_range): standard = normalize_vec2d((to_pt[0] - from_pt[0], to_pt[1] - from_pt[1])) - normal = (standard[1], standard[0]) + normal = (standard[1], -standard[0]) def statements(): for i in range(index, len(self.statements)): yield self.statements[i] -- cgit