如何创建具有边和角的三角形图像
How to create an image of a triangle with sides and angles
正如问题所说,如何创建输入边和角的三角形图像文件。
我目前使用的解决方案是海龟库
forward(s1)
left(180-c)
forward(s2)
left(180-a)
forward(s3)
ts = turtle.getcanvas()
ts.postscript(file="file.ps")
现在可以了,但它会在 ps 文件中输出图像。因为我想要它的图像形式(比如 png/jpg/pil 图像),所以我需要将它转换成它。所以我发现你可以使用
img = Image.open("file.ps")
img.save("file.png")
但这表示它“无法在路径上找到 Ghostscript”
但由于我无法在我的设备上安装 ghostscript(由于某些原因),我无法将其转换为图像形式。
所以我的问题是,是否有任何库或任何方法可以仅使用边和角来创建三角形的图像文件。
不知道我如何在 PIL 中做到这一点,因为我需要顶点坐标,而且我不知道如何获取顶点坐标。 Turtle 的另一个问题是它创建了一个新的 window 来制作图像。所以最好是,我希望图像创建在后台发生。有什么办法吗?
编辑:我目前用来制作文件的代码:
def trianglesss(s1,s2,s3):
a = s1
b = s2
c = s3
a1 = round(math.degrees(math.acos(((b**2)+(c**2)-(a**2))/(2*b*c))))
b1 = round(math.degrees(math.acos(((c**2)+(a**2)-(b**2))/(2*a*c))))
c1 = round(math.degrees(math.acos(((b**2)+(a**2)-(c**2))/(2*a*b))))
turtle.tracer(0,0)
turtle.pendown()
turtle.speed('fastest')
hideturtle()
forward(s1)
left(180-c1)
forward(s2)
left(180-a1)
forward(s3)
turtle.update()
ts = turtle.getcanvas()
ts.postscript(file="file.eps")
bye()
trisssimg = Image.open("file.eps")
trisssimg.save("Trisss.jpg")
trianglesss(20,20,20)
#Calculating angles using the formula from:
#https://www.mathsisfun.com/algebra/trig-solving-sss-triangles.html
由于 turtle
模块基于 tkinter
,您可以使用 PIL 来实现,如下所示。
import math
from PIL import ImageGrab
import tkinter as tk
import tkinter.messagebox as tkMessageBox
from tkinter.constants import *
import turtle
WIDTH, HEIGHT = 500, 400
IMG_FILENAME = 'turtlescreen.png' # Extension determines file format.
def trianglesss(t, s1, s2, s3):
a = s1
b = s2
c = s3
a1 = round(math.degrees(math.acos(((b**2)+(c**2)-(a**2)) / (2*b*c))))
b1 = round(math.degrees(math.acos(((c**2)+(a**2)-(b**2)) / (2*a*c))))
c1 = round(math.degrees(math.acos(((b**2)+(a**2)-(c**2)) / (2*a*b))))
t.pendown()
t.forward(s1)
t.left(180-c1)
t.forward(s2)
t.left(180-a1)
t.forward(s3)
def draw_stuff(canvas):
screen = turtle.TurtleScreen(canvas)
t = turtle.RawTurtle(screen.getcanvas())
t.speed(0) # Fastest.
t.pencolor('black')
t.hideturtle()
trianglesss(t, 200, 200, 200)
def image_grab(root, widget):
x = root.winfo_rootx() + widget.winfo_x()
y = root.winfo_rooty() + widget.winfo_y()
x1 = x + widget.winfo_width()
y1 = y + widget.winfo_height()
return ImageGrab.grab().crop((x, y, x1, y1))
def save_file(root, canvas, filename):
""" Convert the Canvas widget into an image file. """
# Get image of Canvas and save it to a file.
img = image_grab(root, canvas)
img.save(IMG_FILENAME) # Save image file.
tkMessageBox.showinfo("Info", "Image saved as %r" % filename, parent=root)
# Main
root = tk.Tk()
canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT,
borderwidth=0, highlightthickness=0)
canvas.pack()
btn_frame = tk.Frame(root)
btn_frame.pack()
btn1 = tk.Button(btn_frame, text='Draw', command=lambda: draw_stuff(canvas))
btn1.pack(side=LEFT)
btn2 = tk.Button(btn_frame, text='Save',
command=lambda: save_file(root, canvas, IMG_FILENAME))
btn2.pack(side=LEFT)
btn3 = tk.Button(btn_frame, text='Quit', command=root.quit)
btn3.pack(side=LEFT)
root.mainloop()
截图运行:
您可以使用 Image 和 ImageDraw 在图像上画线。
这里按照海龟概念的一部分给出画线的命令。
from math import cos, sin, pi, ceil
from PIL import Image, ImageDraw
def draw(commands, filename=None, size=None, show=True):
x0, y0 = 0, 0
direction = 0
line_width, line_color = 1, 'black'
pen_down = False
points = []
for command, value in commands:
cmd = command.strip().lower()
if cmd == "color":
line_color = value
elif cmd == "width":
line_width = value
elif cmd in ("forward", "fd", "backward", "bk"):
distance = value
radian = direction/180*pi if cmd in ("forward", "fd") else (direction+180)/180*pi
x1, y1 = x0 + distance * cos(radian), y0 + distance * sin(radian)
if pen_down:
points.append([(x0, y0), (x1, y1), line_color, line_width])
x0, y0 = x1, y1
elif cmd == "left":
direction -= value
elif cmd == "right":
direction += value
elif cmd in ("penup", "pu"):
pen_down = False
elif cmd in ("pendown", "pd"):
pen_down = True
xs, ys = [], []
for point1, point2, color, width in points:
xs += [point1[0], point2[0]]
ys += [point1[1], point2[1]]
x_min, x_max, y_min, y_max = min(xs), max(xs), min(ys), max(ys)
w, h = ceil(x_max - x_min + 1), ceil(y_max - y_min + 1)
width, height = size if size else (w, h)
dx, dy = (width - w)/2 - x_min, (height - h)/2 - y_min
im = Image.new(mode="RGBA", size=(width, height), color=(0, 0, 0, 0))
draw = ImageDraw.Draw(im, mode="RGBA")
for point1, point2, line_color, line_width in points:
p1, p2 = (point1[0]+dx, point1[1]+dy), (point2[0]+dx, point2[1]+dy)
draw.line([p1, p2], fill=line_color, width=line_width)
if filename:
im.save(filename)
if show:
im.show()
commands = [("PenDown", None), ("Width", 5), ("Color", "blue"),
("FD", 100), ("Left", 120), ("FD", 100), ("left", 120), ("FD", 100)]
draw(commands, "Triangle.png", (200, 200))
正如问题所说,如何创建输入边和角的三角形图像文件。
我目前使用的解决方案是海龟库
forward(s1)
left(180-c)
forward(s2)
left(180-a)
forward(s3)
ts = turtle.getcanvas()
ts.postscript(file="file.ps")
现在可以了,但它会在 ps 文件中输出图像。因为我想要它的图像形式(比如 png/jpg/pil 图像),所以我需要将它转换成它。所以我发现你可以使用
img = Image.open("file.ps")
img.save("file.png")
但这表示它“无法在路径上找到 Ghostscript” 但由于我无法在我的设备上安装 ghostscript(由于某些原因),我无法将其转换为图像形式。 所以我的问题是,是否有任何库或任何方法可以仅使用边和角来创建三角形的图像文件。 不知道我如何在 PIL 中做到这一点,因为我需要顶点坐标,而且我不知道如何获取顶点坐标。 Turtle 的另一个问题是它创建了一个新的 window 来制作图像。所以最好是,我希望图像创建在后台发生。有什么办法吗?
编辑:我目前用来制作文件的代码:
def trianglesss(s1,s2,s3):
a = s1
b = s2
c = s3
a1 = round(math.degrees(math.acos(((b**2)+(c**2)-(a**2))/(2*b*c))))
b1 = round(math.degrees(math.acos(((c**2)+(a**2)-(b**2))/(2*a*c))))
c1 = round(math.degrees(math.acos(((b**2)+(a**2)-(c**2))/(2*a*b))))
turtle.tracer(0,0)
turtle.pendown()
turtle.speed('fastest')
hideturtle()
forward(s1)
left(180-c1)
forward(s2)
left(180-a1)
forward(s3)
turtle.update()
ts = turtle.getcanvas()
ts.postscript(file="file.eps")
bye()
trisssimg = Image.open("file.eps")
trisssimg.save("Trisss.jpg")
trianglesss(20,20,20)
#Calculating angles using the formula from:
#https://www.mathsisfun.com/algebra/trig-solving-sss-triangles.html
由于 turtle
模块基于 tkinter
,您可以使用 PIL 来实现,如下所示。
import math
from PIL import ImageGrab
import tkinter as tk
import tkinter.messagebox as tkMessageBox
from tkinter.constants import *
import turtle
WIDTH, HEIGHT = 500, 400
IMG_FILENAME = 'turtlescreen.png' # Extension determines file format.
def trianglesss(t, s1, s2, s3):
a = s1
b = s2
c = s3
a1 = round(math.degrees(math.acos(((b**2)+(c**2)-(a**2)) / (2*b*c))))
b1 = round(math.degrees(math.acos(((c**2)+(a**2)-(b**2)) / (2*a*c))))
c1 = round(math.degrees(math.acos(((b**2)+(a**2)-(c**2)) / (2*a*b))))
t.pendown()
t.forward(s1)
t.left(180-c1)
t.forward(s2)
t.left(180-a1)
t.forward(s3)
def draw_stuff(canvas):
screen = turtle.TurtleScreen(canvas)
t = turtle.RawTurtle(screen.getcanvas())
t.speed(0) # Fastest.
t.pencolor('black')
t.hideturtle()
trianglesss(t, 200, 200, 200)
def image_grab(root, widget):
x = root.winfo_rootx() + widget.winfo_x()
y = root.winfo_rooty() + widget.winfo_y()
x1 = x + widget.winfo_width()
y1 = y + widget.winfo_height()
return ImageGrab.grab().crop((x, y, x1, y1))
def save_file(root, canvas, filename):
""" Convert the Canvas widget into an image file. """
# Get image of Canvas and save it to a file.
img = image_grab(root, canvas)
img.save(IMG_FILENAME) # Save image file.
tkMessageBox.showinfo("Info", "Image saved as %r" % filename, parent=root)
# Main
root = tk.Tk()
canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT,
borderwidth=0, highlightthickness=0)
canvas.pack()
btn_frame = tk.Frame(root)
btn_frame.pack()
btn1 = tk.Button(btn_frame, text='Draw', command=lambda: draw_stuff(canvas))
btn1.pack(side=LEFT)
btn2 = tk.Button(btn_frame, text='Save',
command=lambda: save_file(root, canvas, IMG_FILENAME))
btn2.pack(side=LEFT)
btn3 = tk.Button(btn_frame, text='Quit', command=root.quit)
btn3.pack(side=LEFT)
root.mainloop()
截图运行:
您可以使用 Image 和 ImageDraw 在图像上画线。 这里按照海龟概念的一部分给出画线的命令。
from math import cos, sin, pi, ceil
from PIL import Image, ImageDraw
def draw(commands, filename=None, size=None, show=True):
x0, y0 = 0, 0
direction = 0
line_width, line_color = 1, 'black'
pen_down = False
points = []
for command, value in commands:
cmd = command.strip().lower()
if cmd == "color":
line_color = value
elif cmd == "width":
line_width = value
elif cmd in ("forward", "fd", "backward", "bk"):
distance = value
radian = direction/180*pi if cmd in ("forward", "fd") else (direction+180)/180*pi
x1, y1 = x0 + distance * cos(radian), y0 + distance * sin(radian)
if pen_down:
points.append([(x0, y0), (x1, y1), line_color, line_width])
x0, y0 = x1, y1
elif cmd == "left":
direction -= value
elif cmd == "right":
direction += value
elif cmd in ("penup", "pu"):
pen_down = False
elif cmd in ("pendown", "pd"):
pen_down = True
xs, ys = [], []
for point1, point2, color, width in points:
xs += [point1[0], point2[0]]
ys += [point1[1], point2[1]]
x_min, x_max, y_min, y_max = min(xs), max(xs), min(ys), max(ys)
w, h = ceil(x_max - x_min + 1), ceil(y_max - y_min + 1)
width, height = size if size else (w, h)
dx, dy = (width - w)/2 - x_min, (height - h)/2 - y_min
im = Image.new(mode="RGBA", size=(width, height), color=(0, 0, 0, 0))
draw = ImageDraw.Draw(im, mode="RGBA")
for point1, point2, line_color, line_width in points:
p1, p2 = (point1[0]+dx, point1[1]+dy), (point2[0]+dx, point2[1]+dy)
draw.line([p1, p2], fill=line_color, width=line_width)
if filename:
im.save(filename)
if show:
im.show()
commands = [("PenDown", None), ("Width", 5), ("Color", "blue"),
("FD", 100), ("Left", 120), ("FD", 100), ("left", 120), ("FD", 100)]
draw(commands, "Triangle.png", (200, 200))