Correctly find the center for single quadrant arcs

This commit is contained in:
Garret Fick 2016-04-23 13:32:32 +08:00
parent 2eac1e427c
commit af86c5c5a2
2 changed files with 38 additions and 1 deletions

View file

@ -21,6 +21,7 @@
import copy
import json
import re
import sys
try:
from cStringIO import StringIO
@ -30,6 +31,7 @@ except(ImportError):
from .gerber_statements import *
from .primitives import *
from .cam import CamFile, FileSettings
from .utils import sq_distance
def read(filename):
@ -548,7 +550,7 @@ class GerberParser(object):
else:
i = 0 if stmt.i is None else stmt.i
j = 0 if stmt.j is None else stmt.j
center = (start[0] + i, start[1] + j)
center = self._find_center(start, end, (i, j))
if self.region_mode == 'off':
self.primitives.append(Arc(start, end, center, self.direction, self.apertures[self.aperture], quadrant_mode=self.quadrant_mode, level_polarity=self.level_polarity, units=self.settings.units))
else:
@ -579,6 +581,35 @@ class GerberParser(object):
self.primitives.append(primitive)
self.x, self.y = x, y
def _find_center(self, start, end, offsets):
"""
In single quadrant mode, the offsets are always positive, which means there are 4 possible centers.
The correct center is the only one that results in an arc with sweep angle of less than or equal to 90 degrees
"""
if self.quadrant_mode == 'single-quadrant':
# The Gerber spec says single quadrant only has one possible center, and you can detect
# based on the angle. But for real files, this seems to work better - there is usually
# only one option that makes sense for the center (since the distance should be the same
# from start and end). Find the center that makes the most sense
sqdist_diff_min = sys.maxint
center = None
for factors in [(1, 1), (1, -1), (-1, 1), (-1, -1)]:
test_center = (start[0] + offsets[0] * factors[0], start[1] + offsets[1] * factors[1])
sqdist_start = sq_distance(start, test_center)
sqdist_end = sq_distance(end, test_center)
if abs(sqdist_start - sqdist_end) < sqdist_diff_min:
center = test_center
sqdist_diff_min = abs(sqdist_start - sqdist_end)
return center
else:
return (start[0] + offsets[0], start[1] + offsets[1])
def _evaluate_aperture(self, stmt):
self.aperture = stmt.d

View file

@ -297,3 +297,9 @@ def nearly_equal(point1, point2, ndigits = 6):
'''Are the points nearly equal'''
return round(point1[0] - point2[0], ndigits) == 0 and round(point1[1] - point2[1], ndigits) == 0
def sq_distance(point1, point2):
diff1 = point1[0] - point2[0]
diff2 = point1[1] - point2[1]
return diff1 * diff1 + diff2 * diff2