def _find_circle_center(self, start0, start1, end0, end1, radius): """each circle defines all possible coordinates the arc center could be the two circles intersect at the possible centers of the arc radius""" c1 = sp.Circle(sp.Point(start0, start1), abs(radius)) c2 = sp.Circle(sp.Point(end0, end1), abs(radius)) intersection = c1.intersection(c2) if len(intersection) < 1: raise Exception( "radius circles do not intersect") # TODO : proper way of handling GCode error (?) if len( intersection) < 2 or radius > 0: # single intersection or "positive" radius center point return intersection[0].x, intersection[0].y return intersection[1].x, intersection[1].y # "negative" radius center point
def __init__(self, x, y, radius, estimateRadius=None, key=None): self.x = x self.y = y self.radius = radius #self.area = math.pi * radius**2 self.estimateRadius = estimateRadius self.key = key self.circle = sympy.Circle(sympy.Point(self.x, self.y), radius)
def read_dial(config, idx, img): offset, clockwise = config offset_r = offset * (np.pi / 180) height, width = img.shape[:2] center = [width / 2, height / 2] radius = int(width / 2) circle = sp.Circle(sp.Point(center), radius) offset_ray = sp.Ray(sp.Point(center), angle=mp.radians(offset)) offset_img = img.copy() origin_point = [center[0], 0] offset_point = [ math.cos(offset_r) * (origin_point[0] - center[0]) - math.sin(offset_r) * (origin_point[1] - center[1]) + center[0], math.sin(offset_r) * (origin_point[0] - center[0]) + math.cos(offset_r) * (origin_point[1] - center[1]) + center[1] ] cv2.line(offset_img, (int(center[0]), int(center[1])), (int(offset_point[0]), int(offset_point[1])), (0, 255, 0), 2) write_debug(offset_img, f"dial-{idx}") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (5, 5), 0) write_debug(blurred, f"blurred-{idx}") edges = cv2.Canny(blurred, 50, 200) write_debug(edges, f"edges-{idx}") edge = find_hand_edge(edges) hand_edge_img = img.copy() cv2.line(hand_edge_img, (edge[0], edge[1]), (edge[2], edge[3]), (0, 255, 0), 2) write_debug(hand_edge_img, f"hand-edge-{idx}") hand_ray = generate_hand_ray(center, edge) circle_intersection = hand_ray.intersection(circle)[0] cv2.line(img, (int(center[0]), int(center[1])), (int(circle_intersection.x), int(circle_intersection.y)), (0, 0, 255), 2) write_debug(img, f"intersection-{idx}") angle_r = math.atan2(circle_intersection.y - center[1], circle_intersection.x - center[0]) - math.atan2( origin_point[1] - center[1], origin_point[0] - center[0]) angle = angle_r * 180 / np.pi if angle < 0: angle = 360 + angle angle_p = angle / 360 if not clockwise: angle_p = 1 - angle_p return int(10 * angle_p)
def transform_sequence(self, operTypes, operVals, operRefs): ''' ArcModified class this method performs a sequence of transformation processes expressed by * operTypes: defines the type of each transformation * operVals: the values for each transformation * operRefs: the reference point for each transformation -- reference point is irrelevant for translation, still should be provided for consistency example: obj.transform_sequence( operTypes='TTRST', operVals=( (.5,-.5), (2,0), np.pi/2, (.5,.5), (3,-1) ), operRefs=( (0,0), (0,0), (2,2), (0,0), (0,0) ) ) order: ordering of transformation e.g. 'TRS' -> 1)translate 2)rotate 3)scale e.g. 'RTS' -> 1)rotate 2)translate 3)scale ''' for opIdx, opType in enumerate(operTypes): if opType == 'T': # and all(operVals[opIdx]!=(0,0)): tx, ty = operVals[opIdx] self.obj = self.obj.translate(tx, ty) elif opType == 'R': # and operVals[opIdx]!=0: theta = operVals[opIdx] ref = operRefs[opIdx] # Important note ideally I would like to do this: # self.obj = self.obj.rotate(theta,ref) but as rotate # is not effective for circles (don't know why!) and # since I can not set the attributes of the circel as: # self.obj.center = self.obj.center.rotate(theta,ref) # I am left with no choice but to define a new circle # and assign it to the obj fortunately this won't be a # problem, as this obj instance is an attribute to the # modifiedCircle instance, and that's what I want to # maintain a reference to c = self.obj.center.rotate(theta, ref) r = self.obj.radius self.obj = sym.Circle(c, r) # TODO: too many consequtive rotation might carry t1 # and t2 out of the predefined interval correct them # if there is going to be any valid interval for t1 # and t2 self.t1 += theta self.t2 += theta elif opType == 'S': # and all(operVals[opIdx]!=(1,1)): sx, sy = operVals[opIdx] ref = operRefs[opIdx] self.obj = self.obj.scale(sx, sy, ref)
def __init__(self, args): ''' ArcModified class ''' self.obj = sym.Circle(*args[:2]) # the radial distance of t1 to t2 can not be more than 2pi # assert max(args[2])-min(args[2]) < 2*np.pi if not (max(args[2]) - min(args[2]) < 2 * np.pi): raise AssertionError() # make sure t1 and t2 are sorted CCW (t1<t2) self.t1 = min(args[2]) self.t2 = max(args[2])
def _clip_path(origin, radius, path): path = np.array(path) prev_pt = origin while len(path) > 0: next_pt = path[0] d = np.linalg.norm(next_pt - origin) if d < radius: path = path[1:] else: intersections = sympy.intersection( sympy.Segment(prev_pt, next_pt), sympy.Circle(origin, radius)) # intersection might not actually happen due to limited # fp precision in np.linalg.norm. if not, continue. if intersections: pt = intersections[0].evalf() origin = np.array([pt.x, pt.y], dtype=path.dtype) return np.vstack([[origin], path]) else: path = path[1:] return path
def to_sympy(self): return sympy.Circle(self._center.to_sympy, self._radius)
def __init__(self, args): ''' CircleModified class ''' self.obj = sym.Circle(*args)
import sympy as sy c1 = sy.Circle(sy.Point(0, 0), 3) c2 = sy.Circle(sy.Point(3, 0), 3) print(c1.encloses(c2))