0

Just as the question says, how do i create an image file of a triangle in which the sides and the angles are inputted.

The current solution i am using is with turtle library

forward(s1)
left(180-c)
forward(s2)
left(180-a)
forward(s3)
ts = turtle.getcanvas()
ts.postscript(file="file.ps")

Now this works, but it outputs the image in a ps file. Since i want it in a image form(like png/jpg/pil image), i need to convert it to it. So i found that to do that you can use

img = Image.open("file.ps")
img.save("file.png")

But that says it "unable to locate Ghostscript on paths" But since i cannot install ghostscript(Due to reasons) on my device, i cant convert it to am image form. So my question is, is there any library or any way to create an image file of a triangle using just the sides and angles. No idea how i could do it in PIL, as i need coordinates for the vertices, and i have no clue how to get the coordinates of the vertices. Also another problem with Turtle is that it creates a new window to make the image. So preferably, i want the image creation to happen in the background. Any way to do this?

Edit: Code i am currently using to make the file:

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

2 Answers2

1

Since the turtle module is based on tkinter, you can do it with the PIL something like the following.

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()

Screenshot of it running:

screenshot

martineau
  • 119,623
  • 25
  • 170
  • 301
  • Thank you, it works. Also i removed the buttons for drawing and saving and just call the drawing and saving functions in the main, as i want this to be automated. Can you tell how to do the quit command after the drawing and saving? As the button works, but i want it to automatically quit after drawing and saving. Again thanks for the help. – Tejasisamazing Aug 09 '21 at 05:02
  • Also, is it possible to do the saving work and the creation of the triangle in the background? Thanks – Tejasisamazing Aug 09 '21 at 05:17
  • You can call `root.quit()` to terminate the `mainloop()`. I don't think you can create the triangle in the background, although I'm not completely sure what you mean. This works by taking a screenshot of the drawing made by `turtle`, so the screen has to be visible. – martineau Aug 09 '21 at 08:01
1

You can use Image and ImageDraw to draw line on image. Here, follow part of the turtle concept to give command to draw lines.

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))

enter image description here

Jason Yang
  • 11,284
  • 2
  • 9
  • 23