def try_close(outline2, distance_th): if len(outline2) <= 2 or outline2.is_closed: return outline2 elif distance_squared(outline2[0], outline2[-1]) <= distance_th: return Outline2(points=outline2.points[:-1], inside_map=outline2.inside_map) else: return outline2
def merge_outlines(outline2_a, outline2_b, distance_sq_th): assert isinstance(outline2_a, Outline2) assert len(outline2_a) > 0 assert isinstance(outline2_b, Outline2) assert len(outline2_b) > 0 assert distance_squared(outline2_a[-1], outline2_b[0]) < distance_sq_th return Outline2(points=outline2_a.points[:-1] + outline2_b.points, inside_map=outline2_a.inside_map + outline2_b.inside_map)
def make_consistent(outline2): if not outline2.is_closed: return outline2 min_pt_idx = min(range(len(outline2)), key=lambda i: outline2.points[i]) return Outline2(points=_rotate_first(outline2.points, min_pt_idx), inside_map=_rotate_first(outline2.inside_map, min_pt_idx))
def compute_profile2(drawing, distance_th=0.5, has_rot_axis=True, regular_y=False): assert BASE_INNER_PROFILE_ID in drawing assert BASE_OUTER_PROFILE_ID in drawing if has_rot_axis and ROTATION_AXIS_ID not in drawing: raise DrawingError('Missing rotation axis') outlines = [] # To gaurantee consistant output, always sort the outlines by name for name, old_outline in sorted(drawing.outlines.items()): assert isinstance(old_outline, Outline) if 'handle' in name or name == ROTATION_AXIS_ID: continue elif 'fracture' in name: o_type = Outline2.NEITHER elif 'inner_base' in name: o_type = Outline2.INSIDE elif 'outer_base' in name: o_type = Outline2.OUTSIDE else: raise DrawingError('Unknown segment %s' % name) outlines.append( Outline2(points=old_outline.points, inside_map=[o_type] * (len(old_outline) - 1))) # Try merging all pairs of outlines that can be merged while len(outlines) > 1: n = len(outlines) # Find the pair of outlines with the lowest merge distance i, j = min(((i, j) for i in range(n) for j in range(i + 1, n)), key=lambda pair: min_merge_distance(outlines[pair[0]], outlines[pair[1]])) outline_a = outlines[i] outline_b = outlines[j] combined = try_combine_outlines(outline_a, outline_b, distance_th) if combined: # Delete larger index first del outlines[j] del outlines[i] outlines.append(combined) else: break for i, o in enumerate(outlines): outlines[i] = try_close(o, distance_th) if len(outlines) > 1: import ipdb ipdb.set_trace() if has_rot_axis: axis_x = drawing[ROTATION_AXIS_ID].points[0][0] else: axis_x = 0 y_mul = +1 if regular_y else -1 # Now: # 1. Align all outlines so that rotation axis is at X = 0. # 2. Try close every outline if it's already a tight circle outlines = [ try_close(o.transform(lambda p: (p[0] - axis_x, y_mul * p[1])), distance_th) for o in outlines ] # Finally return the result return Profile2(outlines=outlines)