def setUp(self): self.segmentGroup = SegmentGroup() self.segmentGroup2 = SegmentGroup() self.pt1 = Point(0, 0, 0) self.pt2 = Point(100, 0, 100) self.pt3 = Point(100, 0, 0) self.pt4 = Point(0, 0, 100) self.pt5 = Point(-120.12, 0, 214.09) self.pt6 = Point(-179.88, 0, 85.91) self.pt7 = Point(-214.09, 0, 179.88) self.pt8 = Point(-85.91, 0, 120.12) self.pt9 = Point(-164.74, 0, 118.39) self.pt10 = Point(-137.55, 0, 176.70) self.lineSegment1 = Segment(self.pt1, self.pt2) self.lineSegment2 = Segment(self.pt5, self.pt6) self.lineSegment3 = Segment(self.pt9, self.pt10) self.lineSegment4 = Segment(self.pt2, self.pt1) self.inverseLineSegment1 = Segment(self.pt3, self.pt4) self.hfeed = 100 self.vfeed = 50 self.step_over = 1.5 self.finish_passes = 2
def generate_path(self): """Generate the path for the profile operation""" part_boundbox = self.part_segment_group.boundbox() x_min = self.stock.x_min - self.extra_dia * 0.5 - self.clearance x_max = 0 - self.min_dia * 0.5 z_max = self.stock.z_max + self.start_offset self.clearing_paths = [] length = z_max - part_boundbox.z_max + self.stock_to_leave step_over = self.step_over line_count = math.ceil(length / step_over) zstart = part_boundbox.z_max + step_over * line_count + self.stock_to_leave # build list of segments segmentgroup = SegmentGroup() # TODO: Move the final pass to finishing passes for a slower pass counter = 0 while counter < line_count + 1: zpt = zstart - counter * self.step_over pt1 = Point(x_min, 0, zpt) pt2 = Point(x_max, 0, zpt) path_line = Segment(pt1, pt2) seg = path_line segmentgroup.add_segment(seg) pt3 = pt2.project(self.leadout_angle, self.step_over) leadout = Segment(pt2, pt3) segmentgroup.add_segment(leadout) counter += 1 self.clearing_paths.append(segmentgroup)
def boundbox(self): """Return the boundbox for the segmentgroup""" xvalues = [] yvalues = [] zvalues = [] # collect all points from each segment by direction for segment in self.get_segments(): xvalues.extend(segment.get_all_axis_positions('X')) yvalues.extend(segment.get_all_axis_positions('Y')) zvalues.extend(segment.get_all_axis_positions('Z')) x_min = min(xvalues, key=abs) x_max = max(xvalues, key=abs) y_min = min(yvalues, key=abs) y_max = max(yvalues, key=abs) z_min = min(zvalues, key=abs) z_max = max(zvalues, key=abs) pt1 = Point(x_min, y_min, z_min) pt2 = Point(x_max, y_max, z_max) segmentgroupBoundBox = BoundBox(pt1, pt2) return segmentgroupBoundBox
def __init__(self, start=Point(0.0, 0.0, 0.0), end=Point(0.0, 0.0, 0.0), bulge=0.0): self.start = start self.end = end self.bulge = bulge
def setUp(self): self.pt1 = Point(0, 0, 0) self.pt2 = Point(100, 100, 100) self.boundBox1 = BoundBox(self.pt1, self.pt2) self.pt3 = Point(-100, -100, -100.5) self.pt4 = Point(100, 100, 100) self.boundBox2 = BoundBox(self.pt3, self.pt4)
def test_get_centre_point(self): lineCentrePt = self.lineSegment1.get_centre_point() self.assertEqual(lineCentrePt, None) arcCentrePt = self.arcSegment1.get_centre_point() centrePt = Point(70.83333333333333, 0.0, 29.166666666666668) self.assertTrue(arcCentrePt.is_same(centrePt)) invArcCenPt = self.inverseArcSegment1.get_centre_point() centrePt = Point(29.166666666666668, 0.0, 70.83333333333333) self.assertTrue(invArcCenPt.is_same(centrePt))
def z_at_x(self, x): """get the z value at the first intersection at the given x position""" boundbox = self.boundbox() offset = boundbox.z_length() start_pt = Point(x, 0, boundbox.z_max + offset) end_pt = Point(x, 0, boundbox.z_min - offset) line_segment = Segment(start_pt, end_pt) for segment in self.get_segments(): intersect, pts = segment.intersect(line_segment) if intersect: return pts[0].Z return None
def setUp(self): # Define Part Geometry part_segments = [] PartPt1 = Point(0, 0, 10) PartPt2 = Point(-5, 0, -9) PartPt3 = Point(-9.5, 0, -15.85) PartPt4 = Point(-5.4, 0, -22) PartPt5 = Point(-5.4, 0, -40) PartPt6 = Point(-13, 0, -45) PartPt7 = Point(-13, 0, -48) PartPt8 = Point(0, 0, -48) part_segments.append(Segment(PartPt1, PartPt2, -0.75)) part_segments.append(Segment(PartPt2, PartPt3)) part_segments.append(Segment(PartPt3, PartPt4)) part_segments.append(Segment(PartPt4, PartPt5)) part_segments.append(Segment(PartPt5, PartPt6)) part_segments.append(Segment(PartPt6, PartPt8)) part_segments.append(Segment(PartPt7, PartPt8)) # Define stock bounds stockPt1 = Point(0, 0, 15) stockPt2 = Point(-25, 0, -47.5) stock_boundbox = BoundBox(stockPt1, stockPt2) # set feed rate to test self.hfeed = 10 # Define Operations Properties params = {} params['min_dia'] = 0 params['extra_dia'] = 0 params['start_offset'] = 0 params['end_offset'] = 0 params['allow_grooving'] = True params['step_over'] = 1 params['finish_passes'] = 2 params['stock_to_leave'] = 0 params['hfeed'] = self.hfeed params['vfeed'] = 10 self.op = RoughOP() self.op.set_params(params) self.op.add_stock(stock_boundbox) self.op.add_part_edges(part_segments) tool = Tool() tool.set_tool_from_string('DCMT070204R') self.op.add_tool(tool)
def find_next_good_edge(self, current_index, stock_z_min, tool, allow_grooving, pt=None): segments = self.get_segments() index = current_index if pt is None: pt1 = segments[index].start else: pt1 = pt index += 1 while index < len(segments): if allow_grooving: # create a new point at the max angle from pt1 ang = tool.get_tool_cutting_angle() # calculate the length required to project the point to the centreline length = abs(pt1.X / math.cos(math.radians(ang - 90))) pt2 = pt1.project(ang, length) else: pt2 = Point(pt1.X, pt1.Y, stock_z_min) # create a new projected segment seg = Segment(pt1, pt2) # loop through the remaining segments and see if the projected segments idx = index while idx < len(segments): intersect, pts = seg.intersect(segments[idx]) if intersect: return idx, pts[0] idx += 1 index += 1 stock_pt = Point(pt1.X, pt1.Y, stock_z_min) seg = Segment(pt1, stock_pt) index = current_index index += 1 while index < len(segments): intersect, pts = seg.intersect(segments[index]) if intersect: return index, pts[0] index += 1 # No solution :( return False, stock_pt
def test_angle_to(self): angle = self.pt1.angle_to(Point(0, 0, 100)) self.assertEqual(angle, 0) angle = self.pt1.angle_to(Point(100, 0, 100)) self.assertEqual(angle, 45) angle = self.pt1.angle_to(Point(100, 0, 0)) self.assertEqual(angle, 90) angle = self.pt1.angle_to(Point(100, 0, -100)) self.assertEqual(angle, 135) angle = self.pt1.angle_to(Point(0, 0, -100)) self.assertEqual(angle, 180) angle = self.pt1.angle_to(Point(-100, 0, -100)) self.assertEqual(angle, 225) angle = self.pt1.angle_to(Point(-100, 0, 0)) self.assertEqual(angle, 270) angle = self.pt1.angle_to(Point(-100, 0, 100)) self.assertEqual(angle, 315)
def get_centre_point(self): """Returns the centre point of the arc""" if self.bulge == 0: return None normal = math.sqrt( math.pow((self.end.X - self.start.X), 2) + math.pow((self.end.Z - self.start.Z), 2)) basex = math.sqrt( math.pow(self.get_radius(), 2) - math.pow((normal / 2), 2)) * (self.start.Z - self.end.Z) / normal basey = math.sqrt( math.pow(self.get_radius(), 2) - math.pow((normal / 2), 2)) * (self.end.X - self.start.X) / normal # invert for positive bulge values if self.bulge > 0: basex = -basex basey = -basey x = (self.start.X + self.end.X) / 2 + basex z = (self.start.Z + self.end.Z) / 2 + basey p = Point(x, 0, z) return p
def intersect_circle_circle(self, seg, extend=False): # ref http://paulbourke.net/geometry/circlesphere/ c1 = self.get_centre_point() r1 = self.get_radius() c2 = seg.get_centre_point() r2 = seg.get_radius() intersect = False pts = [] ptsout = [] # Determine actual distance between circle centres c_dist = c1.distance_to(c2) if round(c_dist, 5) >= round(r1 + r2, 5): # too far apart to intersect or just touching return intersect, ptsout if c_dist < abs(r1 - r2): # inside each other return intersect, ptsout if c1.is_same(c2) or round(c_dist, 5) == 0: # concentric return intersect, ptsout # get the chord distance a = (r1**2 - r2**2 + c_dist**2) / (2 * c_dist) # A**2 + B**2 = C**2; h**2 + a**2 = r1**2 therefore: h = math.sqrt(r1**2 - a**2) p = c1.lerp(c2, a / c_dist) b = h / c_dist pts.append(Point(p.X - b * (c2.Z - c1.Z), 0, p.Z + b * (c2.X - c1.X))) pts.append(Point(p.X + b * (c2.Z - c1.Z), 0, p.Z - b * (c2.X - c1.X))) for pnt in pts: # check if the point is on both segments if self.point_on_segment(pnt) and seg.point_on_segment(pnt): ptsout.append(pnt) if len(ptsout): intersect = True return intersect, ptsout
def generate_path(self): """Generate the path for the Part operation""" self.tool_paths = [] toolWidth = self.tool.get_width() xmin = self.stock.XMin - self.extra_dia * 0.5 xmax = 0 - self.min_dia * 0.5 zmin = self.stock.ZMin - toolWidth # build list of segments segmentgroup = SegmentGroup() startPt = Point(xmin, 0, zmin) endPt = Point(xmax, 0, zmin) seg = Segment(startPt, endPt) segmentgroup.add_segment(seg) self.tool_paths.append(segmentgroup)
def get_pos(pnt): x = pnt.X y = pnt.Y z = pnt.Z if invert_x: x = 0 - x return Point(x, y, z)
def test_normalise_to(self): normal = self.pt1.normalise_to(Point(100, 0, 100)) self.assertEqual(normal.X, 0.7071067811865475) self.assertEqual(normal.Y, 0) self.assertEqual(normal.Z, 0.7071067811865475) normal = self.pt1.normalise_to(self.pt1) self.assertEqual(normal.X, 0) self.assertEqual(normal.Y, 0) self.assertEqual(normal.Z, 0)
def intersectCircleCircle(self, seg, extend=False): c1 = self.get_centre_point() r1 = self.get_radius() c2 = seg.get_centre_point() r2 = seg.get_radius() intersect = False pts = [] ptsout = [] # Determine actual distance between circle centres c_dist = c1.distance_to(c2) if c_dist > r1 + r2: # too far apart to intersect return intersect, ptsout if c_dist < abs(r1 - r2): # inside each other return intersect, ptsout if c1.is_same(c2): # concentric return intersect, ptsout a = (r1 ** 2 - r2 ** 2 + c_dist ** 2) / (2 * c_dist) h = math.sqrt(r1 ** 2 - a ** 2) p = c1.lerp(c2, a / c_dist) b = h / c_dist pts.append(Point(p.X - b * (c2.Z - c1.Z), 0, p.Z + b * (c2.X - c1.X))) pts.append(Point(p.X + b * (c2.Z - c1.Z), 0, p.Z - b * (c2.X - c1.X))) for pnt in pts: # check if the point is on both segments if self.point_on_segment(pnt) and seg.point_on_segment(pnt): ptsout.append(pnt) if len(ptsout): intersect = True return intersect, ptsout
def setUp(self): self.pt1 = Point(0, 0, 0) self.pt2 = Point(100, 0, 100) self.pt3 = Point(100, 0, 0) self.pt4 = Point(0, 0, 100) self.pt5 = Point(-120.12, 0, 214.09) self.pt6 = Point(-179.88, 0, 85.91) self.pt7 = Point(-214.09, 0, 179.88) self.pt8 = Point(-85.91, 0, 120.12) self.pt9 = Point(-164.74, 0, 118.39) self.pt10 = Point(-137.55, 0, 176.70) self.lineSegment1 = Segment(self.pt1, self.pt2) self.lineSegment2 = Segment(self.pt5, self.pt6) self.lineSegment3 = Segment(self.pt9, self.pt10) self.inverseLineSegment1 = Segment(self.pt3, self.pt4) self.arcSegment1 = Segment(self.pt1, self.pt2, 1.5) self.arcSegment2 = Segment(self.pt7, self.pt8, 1.5) self.arcSegment3 = Segment(self.pt3, self.pt4, 1.5) self.inverseArcSegment1 = Segment(self.pt1, self.pt2, -1.5) self.inverseArcSegment2 = Segment(self.pt7, self.pt8, -1.5)
def intersectLineLine(self, seg, extend=False): a1 = self.start a2 = self.end b1 = seg.start b2 = seg.end intersect = False pts = [] ua_t = (b2.X - b1.X) * (a1.Z - b1.Z) - (b2.Z - b1.Z) * (a1.X - b1.X) ub_t = (a2.X - a1.X) * (a1.Z - b1.Z) - (a2.Z - a1.Z) * (a1.X - b1.X) u_b = (b2.Z - b1.Z) * (a2.X - a1.X) - (b2.X - b1.X) * (a2.Z - a1.Z) if (u_b != 0): ua = ua_t / u_b ub = ub_t / u_b if ((0 <= ua and ua <= 1) and (0 <= ub and ub <= 1)) or extend: intersect = True pt = Point(a1.X + ua * (a2.X - a1.X), 0, a1.Z + ua * (a2.Z - a1.Z)) pts.append(pt) return intersect, pts
def test_intersect(self): intersect, pts = self.lineSegment1.intersect(self.inverseLineSegment1) pt = pts[0] self.assertTrue(intersect) intersectionPt = Point(50, 0.0, 50) self.assertTrue(pt.is_same(intersectionPt)) intersect, pts = self.arcSegment1.intersect(self.inverseLineSegment1) pt = pts[0] self.assertTrue(intersect) intersectionPt = Point(16.666666666666657, 0.0, 83.33333333333334) self.assertTrue(pt.is_same(intersectionPt)) intersect, pts = self.inverseArcSegment1.intersect( self.inverseLineSegment1) pt = pts[0] self.assertTrue(intersect) intersectionPt = Point(83.33333333333334, 0.0, 16.66666666666666) self.assertTrue(pt.is_same(intersectionPt)) intersect, pts = self.arcSegment2.intersect(self.lineSegment2) pt = pts[0] self.assertTrue(intersect) intersectionPt = Point(-130.08000000000004, 0.0, 192.72666666666657) self.assertTrue(pt.is_same(intersectionPt)) intersect, pts = self.inverseArcSegment2.intersect(self.lineSegment2) pt = pts[0] self.assertTrue(intersect) intersectionPt = Point(-169.91999999999996, 0.0, 107.27333333333338) self.assertTrue(pt.is_same(intersectionPt)) intersect, pts = self.arcSegment1.intersect(self.arcSegment3) pt = pts[0] self.assertTrue(intersect) intersectionPt = Point(-2.882525053975556, 0.0, 50) self.assertTrue(pts[0].is_same(intersectionPt)) # false intersection tests intersect, pts = self.inverseArcSegment2.intersect(self.lineSegment1) self.assertFalse(intersect) intersect, pts = self.arcSegment2.intersect(self.lineSegment3) self.assertFalse(intersect)
class test_point(unittest.TestCase): """Test for point.py""" def setUp(self): self.pt1 = Point(0, 0, 0) self.pt2 = Point(100, 100, 100) self.pt3 = Point(150, 130, 200) self.pt4 = Point(200, 200, 200) self.pt5 = Point(-100, 0, 100) self.pt6 = Point(0, 100, 200) self.pt7 = Point(-200, -200, -200) self.pt8 = Point(-400, -400, -400) self.pt9 = Point(-200, -200, -200) self.pt10 = Point(200, 200, 200) def test_distance_to(self): distance = self.pt1.distance_to(self.pt2) self.assertEqual(distance, 173.20508075688772) def test_angle_to(self): angle = self.pt1.angle_to(self.pt2) self.assertEqual(angle, 45) def test_nearest(self): pts = [self.pt2, self.pt3] nearest = self.pt1.nearest(pts) self.assertEqual(nearest, self.pt2) def test_is_same_return_false(self): same = self.pt1.is_same(self.pt2) self.assertFalse(same) def test_is_same_return_true(self): same = self.pt1.is_same(self.pt1) self.assertTrue(same) def test_sub(self): sub = self.pt4.sub(self.pt2) self.assertEqual(sub.X, self.pt2.X) self.assertEqual(sub.Y, self.pt2.Y) self.assertEqual(sub.Z, self.pt2.Z) subNegative = self.pt7.add(self.pt7) self.assertEqual(subNegative.X, self.pt8.X) self.assertEqual(subNegative.Y, self.pt8.Y) self.assertEqual(subNegative.Z, self.pt8.Z) def test_add(self): add = self.pt2.add(self.pt2) self.assertEqual(add.X, self.pt4.X) self.assertEqual(add.Y, self.pt4.Y) self.assertEqual(add.Z, self.pt4.Z) addNegative = self.pt5.add(self.pt2) self.assertEqual(addNegative.X, self.pt6.X) self.assertEqual(addNegative.Y, self.pt6.Y) self.assertEqual(addNegative.Z, self.pt6.Z) def test_multiply(self): multiply = self.pt2.multiply(0) self.assertEqual(multiply.X, self.pt1.X) self.assertEqual(multiply.Y, self.pt1.Y) self.assertEqual(multiply.Z, self.pt1.Z) multiplyNegative = self.pt7.multiply(1) self.assertEqual(multiplyNegative.X, self.pt7.X) self.assertEqual(multiplyNegative.Y, self.pt7.Y) self.assertEqual(multiplyNegative.Z, self.pt7.Z) def test_rotate(self): rotate = self.pt2.rotate(90) self.assertEqual(rotate.X, 100) self.assertEqual(rotate.Y, 100) self.assertEqual(rotate.Z, -100) def test_mid(self): mid = self.pt2.mid(self.pt4) self.assertEqual(mid.X, 150) self.assertEqual(mid.Y, 150) self.assertEqual(mid.Z, 150) def test_project(self): projected = self.pt1.project(270, 5) self.assertEqual(projected.X, self.pt1.X) self.assertEqual(projected.Y, self.pt1.Y) self.assertEqual(projected.Z, -5)
class test_point(unittest.TestCase): """Test for point.py""" def setUp(self): self.pt1 = Point(0, 0, 0) self.pt2 = Point(100, 100, 100) self.pt3 = Point(150, 130, 200) self.pt4 = Point(200, 200, 200) self.pt5 = Point(-100, 0, 100) self.pt6 = Point(0, 100, 200) self.pt7 = Point(-200, -200, -200) self.pt8 = Point(-400, -400, -400) self.pt9 = Point(-200, -200, -200) self.pt10 = Point(200, 200, 200) def test_distance_to(self): distance = self.pt1.distance_to(self.pt2) self.assertEqual(distance, 173.20508075688772) def test_angle_to(self): angle = self.pt1.angle_to(Point(0, 0, 100)) self.assertEqual(angle, 0) angle = self.pt1.angle_to(Point(100, 0, 100)) self.assertEqual(angle, 45) angle = self.pt1.angle_to(Point(100, 0, 0)) self.assertEqual(angle, 90) angle = self.pt1.angle_to(Point(100, 0, -100)) self.assertEqual(angle, 135) angle = self.pt1.angle_to(Point(0, 0, -100)) self.assertEqual(angle, 180) angle = self.pt1.angle_to(Point(-100, 0, -100)) self.assertEqual(angle, 225) angle = self.pt1.angle_to(Point(-100, 0, 0)) self.assertEqual(angle, 270) angle = self.pt1.angle_to(Point(-100, 0, 100)) self.assertEqual(angle, 315) def test_nearest(self): pts = [self.pt2, self.pt3] nearest = self.pt1.nearest(pts) self.assertEqual(nearest, self.pt2) def test_is_same_return_false(self): same = self.pt1.is_same(self.pt2) self.assertFalse(same) def test_is_same_return_true(self): same = self.pt1.is_same(self.pt1) self.assertTrue(same) def test_sub(self): sub = self.pt4.sub(self.pt2) self.assertEqual(sub.X, self.pt2.X) self.assertEqual(sub.Y, self.pt2.Y) self.assertEqual(sub.Z, self.pt2.Z) subNegative = self.pt7.add(self.pt7) self.assertEqual(subNegative.X, self.pt8.X) self.assertEqual(subNegative.Y, self.pt8.Y) self.assertEqual(subNegative.Z, self.pt8.Z) def test_add(self): add = self.pt2.add(self.pt2) self.assertEqual(add.X, self.pt4.X) self.assertEqual(add.Y, self.pt4.Y) self.assertEqual(add.Z, self.pt4.Z) addNegative = self.pt5.add(self.pt2) self.assertEqual(addNegative.X, self.pt6.X) self.assertEqual(addNegative.Y, self.pt6.Y) self.assertEqual(addNegative.Z, self.pt6.Z) def test_multiply(self): multiply = self.pt2.multiply(0) self.assertEqual(multiply.X, self.pt1.X) self.assertEqual(multiply.Y, self.pt1.Y) self.assertEqual(multiply.Z, self.pt1.Z) multiplyNegative = self.pt7.multiply(1) self.assertEqual(multiplyNegative.X, self.pt7.X) self.assertEqual(multiplyNegative.Y, self.pt7.Y) self.assertEqual(multiplyNegative.Z, self.pt7.Z) def test_lerp(self): lerp = self.pt1.lerp(self.pt2, 0.5) self.assertEqual(lerp.X, 50) self.assertEqual(lerp.Y, 50) self.assertEqual(lerp.Z, 50) def test_normalise_to(self): normal = self.pt1.normalise_to(Point(100, 0, 100)) self.assertEqual(normal.X, 0.7071067811865475) self.assertEqual(normal.Y, 0) self.assertEqual(normal.Z, 0.7071067811865475) normal = self.pt1.normalise_to(self.pt1) self.assertEqual(normal.X, 0) self.assertEqual(normal.Y, 0) self.assertEqual(normal.Z, 0) def test_rotate(self): rotate = self.pt2.rotate(90) self.assertEqual(rotate.X, -100) self.assertEqual(rotate.Y, 100) self.assertEqual(rotate.Z, 100) def test_mid(self): mid = self.pt2.mid(self.pt4) self.assertEqual(mid.X, 150) self.assertEqual(mid.Y, 150) self.assertEqual(mid.Z, 150) def test_project(self): projected = self.pt1.project(0, 5) self.assertEqual(projected.X, 0) self.assertEqual(projected.Y, 0) self.assertEqual(projected.Z, 5) projected = self.pt1.project(45, 5) self.assertEqual(projected.X, 3.53553) self.assertEqual(projected.Y, 0) self.assertEqual(projected.Z, 3.53553) projected = self.pt1.project(90, 5) self.assertEqual(projected.X, 5) self.assertEqual(projected.Y, 0) self.assertEqual(projected.Z, 0) projected = self.pt1.project(135, 5) self.assertEqual(projected.X, 3.53553) self.assertEqual(projected.Y, 0) self.assertEqual(projected.Z, -3.53553) projected = self.pt1.project(180, 5) self.assertEqual(projected.X, 0) self.assertEqual(projected.Y, 0) self.assertEqual(projected.Z, -5) projected = self.pt1.project(225, 5) self.assertEqual(projected.X, -3.53553) self.assertEqual(projected.Y, 0) self.assertEqual(projected.Z, -3.53553) projected = self.pt1.project(270, 5) self.assertEqual(projected.X, -5) self.assertEqual(projected.Y, 0) self.assertEqual(projected.Z, 0)
def remove_the_groove(self, stock_z_min, tool, allow_grooving=False): segments = self.get_segments() segs_out = SegmentGroup() index = 0 while index < len(segments): seg = segments[index] next_index = False pt1 = seg.start pt2 = seg.end pt = None # TO DO: Tidy this mess if seg.bulge > 0: segAng = round(math.degrees(seg.get_angle()), 5) # get angle tangent to the start point startPtAng = round( pt1.angle_to(seg.get_centre_point()) - 90, 5) if startPtAng >= tool.get_tool_cutting_angle(): if startPtAng + segAng <= 270: segs_out.add_segment(seg) else: ang = tool.get_tool_cutting_angle() # calculate the length required to project the point to the centreline length = abs(pt1.X / math.cos(math.radians(ang - 90))) proj_pt = pt1.project(ang, length) projseg = Segment(pt1, proj_pt) intersect, pts = projseg.intersect(segments[index]) if intersect and allow_grooving: # add the intersecting line to the segment_group new_seg = Segment(pt1, pts[0]) segs_out.add_segment(new_seg) # add the remainder of the arc to the segment_group remaining_seg = Segment(pts[0], pt2) remaining_seg.derive_bulge(seg) segs_out.add_segment(remaining_seg) else: if seg.start.angle_to(seg.end) <= 180: seg = Segment(pt1, pt2) segs_out.add_segment(seg) else: pt = seg.start next_index, pt = self.find_next_good_edge( index, stock_z_min, tool, allow_grooving, pt) if seg.bulge < 0: # Limit the arc movement to the X extents or the tangent at the max tool angle if allow_grooving angle_limit = 270 if allow_grooving is False else tool.get_tool_cutting_angle( ) + 90 if seg.get_centre_point().angle_to(pt2) >= angle_limit: segs_out.add_segment(seg) else: rad = seg.get_radius() if not allow_grooving: # define a point vertically down on the x axis. x = seg.get_centre_point().X - rad y = seg.get_centre_point().Y z = seg.get_centre_point().Z pt = Point(x, y, z) else: # project a point from the centre of the arc along the angle limit to the radius pt = seg.get_centre_point().project(angle_limit, rad) nseg = Segment(pt1, pt) nseg.derive_bulge(seg, rad) segs_out.add_segment(nseg) pt1 = pt next_index, pt = self.find_next_good_edge( index, stock_z_min, tool, allow_grooving, pt) elif seg.bulge == 0: if pt1.angle_to(pt2) < tool.get_tool_cutting_angle(): next_index, pt = self.find_next_good_edge( index, stock_z_min, tool, allow_grooving) else: segs_out.add_segment(seg) if next_index is False and pt is not None: seg = Segment(pt1, pt) segs_out.add_segment(seg) break if next_index is not False and next_index != index: seg = Segment(pt1, pt) segs_out.add_segment(seg) next_pt1 = pt next_pt2 = segments[next_index].end seg = Segment(next_pt1, next_pt2) seg.derive_bulge(segments[next_index]) segs_out.add_segment(seg) next_index += 1 index = next_index continue index += 1 segs_out.merge_segments() return segs_out
def getliblatheBoundBox(FcBB): liblatheBoundbox = BoundBox(Point(FcBB.XMin, FcBB.YMin, FcBB.ZMin), Point(FcBB.XMax, FcBB.YMax, FcBB.ZMax)) return liblatheBoundbox
def generate_path(self): """Generate the path for the Rough operation""" self.part_segment_group = self.part_segment_group.remove_the_groove( self.stock.z_min, self.tool, self.allow_grooving) self.clearing_paths = [] z_max = self.stock.z_max + self.start_offset + self.clearance line_count = int( math.ceil((self.stock.x_length() + self.extra_dia * 0.5) / self.step_over)) xstart = 0 - (self.step_over * line_count + self.min_dia * 0.5) # create roughing boundary offset by the stock to leave value roughing_boundary = self.part_segment_group.offset_path( self.stock_to_leave) for roughing_pass in range(line_count): xpt = xstart + roughing_pass * self.step_over # check if the roughing pass start is outside the stock boundary_z = roughing_boundary.z_at_x(xpt) if boundary_z and round(boundary_z, 5) >= round( self.stock.z_max, 5): continue pt1 = Point(xpt, 0, z_max) pt2 = Point(xpt, 0, z_max - self.stock.z_length() - self.start_offset) path_line = Segment(pt1, pt2) intersections = [] for seg in roughing_boundary.get_segments(): intersect, point = seg.intersect(path_line) if intersect: for p in point: intersection = Intersection(p, seg) intersections.append(intersection) # build list of segments segmentgroup = SegmentGroup() if not intersections: seg = path_line segmentgroup.add_segment(seg) if len(intersections) == 1: # Only one intersection, trim line to intersection. seg = Segment(pt1, intersections[0].point) segmentgroup.add_segment(seg) if intersections[0].seg: # add lead out startPt = intersections[0].point endPt = startPt.project(self.leadout_angle, self.step_over) path_line = Segment(startPt, endPt) segmentgroup.add_segment(path_line) if len(intersections) > 1: # more than one intersection # add the end points of the pass to generate new segments intersection = Intersection(pt1, None) intersections.insert(0, intersection) intersection2 = Intersection(pt2, None) intersections.append(intersection2) # sort the a list of intersections by their z position intersections = sorted(intersections, key=lambda p: p.point.Z, reverse=True) for i in range(len(intersections)): if i + 1 < len(intersections): if i % 2 == 0: # primary segment primary_segment = Segment( intersections[i].point, intersections[i + 1].point) # check the length of the pass before adding to the segmentgroup if primary_segment.get_length() < self.step_over: continue # if the intersection is connected to another segment if intersections[i].seg: # add a lead in # TODO: optimise this to match the max tool angle endPt = intersections[i].point startPt = endPt.project( self.leadin_angle, self.step_over) path_line = Segment(startPt, endPt) segmentgroup.add_segment(path_line) # add the primary segment to the segment group segmentgroup.add_segment(primary_segment) # if the intersection is connected to another segment if intersections[i + 1].seg: # add a lead out startPt = intersections[i + 1].point endPt = startPt.project( self.leadout_angle, self.step_over) path_line = Segment(startPt, endPt) segmentgroup.add_segment(path_line) if segmentgroup.count(): self.tool_paths.append(segmentgroup)
def remove_the_groove(self, stock_zmin, tool, allow_grooving=False): segments = self.get_segments() segs_out = SegmentGroup() index = 0 while index < len(segments): seg = segments[index] next_index = False pt1 = seg.start pt2 = seg.end pt = None if seg.bulge != 0: print('arc segment') if seg.bulge > 0: # TODO: handle segments with a positive bulge seg = Segment(pt1, pt2) segs_out.add_segment(seg) if seg.bulge < 0: # Limit the arc movement to the X extents or the tangent at the max tool angle if allow_grooving angle_limit = 180 if allow_grooving is False else tool.get_tool_cutting_angle() - 90 if seg.get_centre_point().angle_to(pt2) <= angle_limit: segs_out.add_segment(seg) else: rad = seg.get_radius() if not allow_grooving: x = seg.get_centre_point().X - rad y = seg.get_centre_point().Y z = seg.get_centre_point().Z pt = Point(x, y, z) else: pt = seg.get_centre_point().project(angle_limit, rad) if seg.bulge < 0: rad = 0 - rad seg = Segment(pt1, pt) seg.set_bulge_from_radius(rad) segs_out.add_segment(seg) pt1 = pt next_index, pt = self.find_next_good_edge(index, stock_zmin, tool, allow_grooving, pt) elif seg.bulge == 0: print('line segment') if pt1.angle_to(pt2) > tool.get_tool_cutting_angle(): next_index, pt = self.find_next_good_edge(index, stock_zmin, tool, allow_grooving) else: segs_out.add_segment(seg) if next_index is False and pt is not None: seg = Segment(pt1, pt) segs_out.add_segment(seg) break if next_index is not False and next_index != index: seg = Segment(pt1, pt) segs_out.add_segment(seg) next_pt1 = pt next_pt2 = segments[next_index].end seg = Segment(next_pt1, next_pt2) segs_out.add_segment(seg) next_index += 1 index = next_index continue index += 1 return segs_out
import sys thisFolder = os.path.dirname(os.path.abspath(__file__)) parentFolder = os.path.dirname(thisFolder) sys.path.append(parentFolder) from liblathe.boundbox import BoundBox from liblathe.point import Point from liblathe.profile_op import ProfileOP from liblathe.segment import Segment from liblathe.plot import Plot # Define Part Geometry part_segments = [] PartPt1 = Point(0, 0, 0) PartPt2 = Point(-15, 0, -5) PartPt3 = Point(-15, 0, -15) PartPt4 = Point(0, 0, -20) part_segments.append(Segment(PartPt1, PartPt2)) part_segments.append(Segment(PartPt2, PartPt3)) part_segments.append(Segment(PartPt3, PartPt4)) part_segments.append(Segment(PartPt4, PartPt1)) # Define stock bounds stockPt1 = Point(0, 0, 5) stockPt2 = Point(-20, 0, -20) StockBoundingBox = BoundBox(stockPt1, stockPt2) # Define Operations Properties
def get_part_outline(self): ''' Get Part Outline ''' # TODO: Revisit the edge extraction and find a more elegant method model = self.model[0].Shape # get a section through the part origin on the XZ Plane sections = Path.Area().add(model).makeSections( mode=0, heights=[0.0], project=True, plane=self.stock_silhoutte) part_silhoutte = sections[0].setParams(Offset=0.0).getShape() # get an offset section larger than the part section part_bound_face = sections[0].setParams(Offset=0.1).getShape() # ensure the cutplane is larger than the part or segments will be missed modelBB = model.BoundBox plane_length = modelBB.ZLength * 1.5 plane_width = (modelBB.XLength / 2) * 1.5 z_ref = modelBB.ZMax + (plane_length - modelBB.ZLength) / 2 # create a plane larger than the part cut_plane = Part.makePlane(plane_length, plane_width, FreeCAD.Vector(-plane_width, 0, z_ref), FreeCAD.Vector(0, -1, 0)) # Cut the part section from the cut plane path_area = cut_plane.cut(part_silhoutte) part_edges = [] part_segments = [] # interate through the edges and check if each is inside the bound_face for edge in path_area.Edges: edge_in = True for vertex in edge.Vertexes: if not part_bound_face.isInside(vertex.Point, 0.1, True): edge_in = False if edge_in: part_edges.append(edge) vert = edge.Vertexes pt1 = Point(vert[0].X, vert[0].Y, vert[0].Z) pt2 = Point(vert[-1].X, vert[-1].Y, vert[-1].Z) seg = Segment(pt1, pt2) if isinstance(edge.Curve, Part.Circle): line1 = Part.makeLine(edge.Curve.Location, edge.Vertexes[0].Point) line2 = Part.makeLine(edge.Curve.Location, edge.Vertexes[-1].Point) part_edges.append(line1) part_edges.append(line2) angle = edge.LastParameter - edge.FirstParameter direction = edge.Curve.Axis.y # print('bulge angle', direction, angle * direction) # TODO: set the correct sign for the bulge +- seg.set_bulge(angle * direction) part_segments.append(seg) # path_profile = Part.makeCompound(part_edges) # Part.show(path_profile, 'Final_pass') return part_segments
def setUp(self): self.pt1 = Point(0, 0, 0) self.pt2 = Point(100, 100, 100) self.pt3 = Point(150, 130, 200) self.pt4 = Point(200, 200, 200) self.pt5 = Point(-100, 0, 100) self.pt6 = Point(0, 100, 200) self.pt7 = Point(-200, -200, -200) self.pt8 = Point(-400, -400, -400) self.pt9 = Point(-200, -200, -200) self.pt10 = Point(200, 200, 200)
thisFolder = os.path.dirname(os.path.abspath(__file__)) parentFolder = os.path.dirname(thisFolder) sys.path.append(parentFolder) from liblathe.boundbox import BoundBox from liblathe.point import Point from liblathe.profile_op import ProfileOP from liblathe.segment import Segment from liblathe.plot import Plot from liblathe.tool import Tool # Define Part Geometry part_segments = [] PartPt1 = Point(0, 0, 10) PartPt2 = Point(-5, 0, -9) PartPt3 = Point(-9.5, 0, -15.85) PartPt4 = Point(-5.4, 0, -22) PartPt5 = Point(-5.4, 0, -40) PartPt6 = Point(-13, 0, -45) PartPt7 = Point(-13, 0, -48) PartPt8 = Point(0, 0, -48) part_segments.append(Segment(PartPt1, PartPt2, -0.75)) part_segments.append(Segment(PartPt2, PartPt3)) part_segments.append(Segment(PartPt3, PartPt4)) part_segments.append(Segment(PartPt4, PartPt5)) part_segments.append(Segment(PartPt5, PartPt6)) part_segments.append(Segment(PartPt6, PartPt8)) part_segments.append(Segment(PartPt7, PartPt8))
def multiply(self, val): v = Point(self.X * val, self.Y * val, self.Z * val) return v