使用Turtle绘制多边形剖面线时线条超出边界问题求助
解决Turtle绘制多边形剖面线超出边界的问题
我用Python Turtle编写了一段代码,实现平行剖面线填充多边形,但运行后剖面线会超出多边形边界。
- 当前效果:剖面线从多边形内部延伸到外部,超出了多边形的轮廓
- 预期效果:剖面线完全限制在多边形内部,只显示轮廓内的部分
原始代码
import turtle import math def getPolygonVertices(numVertices): #get polygon vertices function vertices = [] for i in range(numVertices): x = int(input(f"Enter x coordinate of vertex {i+1}: ")) y = int(input(f"Enter y coordinate of vertex {i+1}: ")) vertices.append((x, y)) return vertices def polygon(vertices): #draw polygon function turtle.up() turtle.goto(vertices[0]) turtle.down() for vertex in vertices: turtle.goto(vertex) turtle.goto(vertices[0]) def pointInsidePolygon(point, vertices): #function to check if a point is inside polygon x, y = point inside = False for i in range(len(vertices)): j = (i + 1) % len(vertices) if ((vertices[i][1] > y) != (vertices[j][1] > y)) and \ (x < (vertices[j][0] - vertices[i][0]) * (y - vertices[i][1]) / (vertices[j][1] - vertices[i][1]) + vertices[i][0]): inside = not inside return inside def hatchPolygon(vertices, line_spacing=10, angle=0): turtle.speed(0) turtle.hideturtle() #draw polygon polygon(vertices) #compute and draw hatch lines min_x = min(v[0] for v in vertices) max_x = max(v[0] for v in vertices) min_y = min(v[1] for v in vertices) max_y = max(v[1] for v in vertices) #convert angle to radians radAngle = math.radians(angle) #compute line spacing in x and y direction line_spacing_x = lineSpacing * math.cos(radAngle) line_spacing_y = lineSpacing * math.sin(radAngle) #compute start point start_x = math.floor((min_x + line_spacing_x/2) / line_spacing_x) * line_spacing_x start_y = math.floor((min_y + line_spacing_y/2) / line_spacing_y) * line_spacing_y #compute end point end_x = math.ceil((max_x - line_spacing_x/2) / line_spacing_x) * line_spacing_x end_y = math.ceil((max_y - line_spacing_y/2) / line_spacing_y) * line_spacing_y #draw hatch lines turtle.penup() for y in range(int(start_y), int(end_y), int(line_spacing_y)): for x in range(int(start_x), int(end_x), int(line_spacing_x)): if pointInsidePolygon((x, y), vertices): turtle.goto(x, y) turtle.pendown() turtle.goto(x - line_spacing_x * math.tan(radAngle), y + line_spacing_y) turtle.penup() turtle.done() #Main n = int(input("Enter number of polygon vertices: ")) #get number of vertices polygonVertices = getPolygonVertices(n) #get polygon vertices #hatch line lineSpacing = 10 angle = 45 hatchPolygon(polygonVertices, lineSpacing, angle)
错误原因分析
- 剖面线绘制逻辑错误:当前代码判断一个点在多边形内后,直接从该点绘制一段固定长度的线,这段线的终点大概率在多边形外部,导致剖面线超出边界。
- 变量名不一致:函数
hatchPolygon的参数是line_spacing,但内部使用了全局变量lineSpacing,属于不良编码习惯,容易引发NameError。 - 遍历方式不严谨:用整数步长遍历x/y坐标,会因为角度导致剖面线间距不准确,且没有考虑剖面线与多边形边界的交点,无法精准控制线段的起止位置。
修正后的代码
import turtle import math def getPolygonVertices(numVertices): vertices = [] for i in range(numVertices): x = int(input(f"Enter x coordinate of vertex {i+1}: ")) y = int(input(f"Enter y coordinate of vertex {i+1}: ")) vertices.append((x, y)) return vertices def polygon(vertices): turtle.up() turtle.goto(vertices[0]) turtle.down() for vertex in vertices: turtle.goto(vertex) turtle.goto(vertices[0]) def pointInsidePolygon(point, vertices): x, y = point inside = False for i in range(len(vertices)): j = (i + 1) % len(vertices) if ((vertices[i][1] > y) != (vertices[j][1] > y)) and \ (x < (vertices[j][0] - vertices[i][0]) * (y - vertices[i][1]) / (vertices[j][1] - vertices[i][1]) + vertices[i][0]): inside = not inside return inside def lineIntersection(line1, line2): # 计算两条线段的交点,line1和line2格式为((x1,y1), (x2,y2)) x1, y1 = line1[0] x2, y2 = line1[1] x3, y3 = line2[0] x4, y4 = line2[1] denom = (x1 - x2)*(y3 - y4) - (y1 - y2)*(x3 - x4) if denom == 0: return None # 线段平行或重合,无交点 t_numer = (x1 - x3)*(y3 - y4) - (y1 - y3)*(x3 - x4) u_numer = (x1 - x3)*(y1 - y2) - (y1 - y3)*(x1 - x2) t = t_numer / denom u = u_numer / denom if 0 <= t <= 1 and 0 <= u <= 1: x = x1 + t*(x2 - x1) y = y1 + t*(y2 - y1) return (x, y) return None def hatchPolygon(vertices, line_spacing=10, angle=0): turtle.speed(0) turtle.hideturtle() polygon(vertices) min_x = min(v[0] for v in vertices) max_x = max(v[0] for v in vertices) min_y = min(v[1] for v in vertices) max_y = max(v[1] for v in vertices) radAngle = math.radians(angle) cos_angle = math.cos(radAngle) sin_angle = math.sin(radAngle) # 计算包围盒内所有平行剖面线的偏移值 offsets = [] for x, y in [(min_x, min_y), (min_x, max_y), (max_x, min_y), (max_x, max_y)]: offsets.append(cos_angle * x + sin_angle * y) min_offset = min(offsets) - line_spacing max_offset = max(offsets) + line_spacing current_offset = min_offset while current_offset <= max_offset: intersections = [] # 遍历多边形每条边,计算与当前剖面线的交点 for i in range(len(vertices)): j = (i + 1) % len(vertices) edge = (vertices[i], vertices[j]) # 构造足够长的剖面线,确保穿过整个包围盒 if abs(cos_angle) > abs(sin_angle): x1 = min_x - 100 y1 = (current_offset - cos_angle * x1) / sin_angle if sin_angle != 0 else 0 x2 = max_x + 100 y2 = (current_offset - cos_angle * x2) / sin_angle if sin_angle != 0 else 0 else: y1 = min_y - 100 x1 = (current_offset - sin_angle * y1) / cos_angle if cos_angle != 0 else 0 y2 = max_y + 100 x2 = (current_offset - sin_angle * y2) / cos_angle if cos_angle != 0 else 0 hatch_line = ((x1, y1), (x2, y2)) intersect = lineIntersection(edge, hatch_line) if intersect is not None: intersections.append(intersect) # 对交点按剖面线方向排序,确保连接顺序正确 if len(intersections) >= 2: def param(point): return cos_angle * point[0] - sin_angle * point[1] intersections.sort(key=param) # 两两连接交点,只保留多边形内部的线段 turtle.penup() for k in range(0, len(intersections), 2): if k+1 >= len(intersections): break p1 = intersections[k] p2 = intersections[k+1] # 验证线段中点是否在多边形内,避免错误连接外部交点 mid_x = (p1[0] + p2[0])/2 mid_y = (p1[1] + p2[1])/2 if pointInsidePolygon((mid_x, mid_y), vertices): turtle.goto(p1) turtle.pendown() turtle.goto(p2) turtle.penup() current_offset += line_spacing turtle.done() # Main n = int(input("Enter number of polygon vertices: ")) polygonVertices = getPolygonVertices(n) lineSpacing = 10 angle = 45 hatchPolygon(polygonVertices, lineSpacing, angle)
关键修正点
- 新增线段交点计算:通过
lineIntersection函数精准计算剖面线与多边形边的交点,确保只绘制多边形内部的线段部分。 - 重构剖面线生成逻辑:基于偏移值生成所有平行剖面线,对每条线的交点排序后,连接内部的交点对,完全贴合多边形边界。
- 修复变量名问题:统一使用函数参数
line_spacing,避免全局变量依赖。 - 添加中点验证:确保连接的交点对之间的线段确实在多边形内部,排除外部交点的错误连接。
内容的提问来源于stack exchange,提问作者krit
相关产品推荐
相关产品推荐

