Skip to content
This repository has been archived by the owner on Oct 12, 2020. It is now read-only.

Commit

Permalink
Added two more tests and one more feature
Browse files Browse the repository at this point in the history
An option has been added to draw open or closed figures. When this 
option is off, the last point and the first point will not be joined or 
else they will be joined
  • Loading branch information
sumagnadas committed May 19, 2020
1 parent 9a59812 commit 8605277
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 188 deletions.
40 changes: 28 additions & 12 deletions modules/geometry.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from PySide2.QtCore import QPoint
from PySide2.QtCore import QPoint, Qt
from PySide2 import QtGui


class Point(QPoint):
Expand All @@ -11,17 +12,32 @@ def __init__(self, x=0, y=0):
y = -y + 299
super().__init__(x, y)

def plot(p, points):
def plot(window, closedflag):
graph = QtGui.QImage()
graph.load("resources/graph.png")
pen = QtGui.QPen(Qt.black, 5, Qt.SolidLine)
p = QtGui.QPainter()
p.begin(graph)
p.setPen(pen)
try:
for i in range(0, len(points)):
p1 = Point(int(points[i][0].text()),
int(points[i][1].text()))
p2 = Point(int(points[i + 1][0].text()),
int(points[i + 1][1].text()))
for i in range(0, len(window.points)):
p1 = Point(int(window.points[i][0].text()),
int(window.points[i][1].text()))
p2 = Point(int(window.points[i + 1][0].text()),
int(window.points[i + 1][1].text()))
p.drawLine(p1.x(), p1.y(), p2.x(), p2.y())
except IndexError:
p1 = Point(int(points[-1][0].text()),
int(points[-1][1].text()))
p2 = Point(int(points[0][0].text()),
int(points[0][1].text()))
p.drawLine(p1.x(), p1.y(), p2.x(), p2.y())
if closedflag:
p1 = Point(int(window.points[-1][0].text()),
int(window.points[-1][1].text()))
p2 = Point(int(window.points[0][0].text()),
int(window.points[0][1].text()))
p.drawLine(p1.x(), p1.y(), p2.x(), p2.y())
else:
pass
p.end()
window.shapeInfo.updateInfo(window.points,
window.shapeName,
window.pointNum,
closedflag)
window.image.setPixmap(QtGui.QPixmap().fromImage(graph))
214 changes: 90 additions & 124 deletions modules/gui/__init__.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,23 @@
from PySide2 import QtWidgets, QtGui, QtCore
from PySide2.QtWidgets import QFileDialog, QDialog
from PySide2.QtWidgets import QFileDialog, QDialog, QCheckBox
from .input import NumInput, ShapeList, PointInput
from .info import ExtraInfo
from os.path import abspath
from modules import geometry
import datetime
import math

shapes = {
3: 'Triangle',
4: 'Quadrilateral',
5: 'Pentagon',
6: 'Hexagon',
7: 'Septagon',
8: 'Octagon',
9: 'Enneagon',
10: 'Decagon'
}


class Graph(QtWidgets.QWidget):
"""Class which defines the window of the application"""

def __init__(self):
super().__init__()

### Some values and widgets needed for the window ###
self.closedFigure = False
self.beingTested = False
self.errorSaving = QtWidgets.QDialog()
self.fileDir = ''
self.save_call = False
self.draw_call = False
self.pointNum = 3
self.image = QtWidgets.QLabel() # Image container for the graph

Expand All @@ -47,41 +35,59 @@ def __init__(self):
self.y_coord2 = NumInput() # input boxes for the coordinates
self.points[1].extend([self.x_coord2, self.y_coord2])

# Buttons for plotting the graph and clearing the text boxes
### Buttons for plotting the graph and clearing the text boxes ###

# 'Draw' Button to draw the line using user-given coordinates
drawButton = QtWidgets.QPushButton(self.tr("Draw"),
clicked=self.draw)

# 'Reset' Button to clear everything in the input boxes
clearButton = QtWidgets.QPushButton(self.tr("Reset"),
clicked=self.clear)

# Save Button for saving the plotted graph with transparent background
save = QtWidgets.QPushButton(self.tr("Save this Graph"),
clicked=self.save)

# Widget containing the 'Draw', 'Save this Graph' and 'Reset' button
# Checkbox for choosing whether or not to connect the last and the first point
closedfigure = QCheckBox("Closed Figure?")
closedfigure.setCheckState(QtCore.Qt.CheckState.Checked)
closedfigure.stateChanged.connect(self.shapeNameChange)

### Widget containing the main buttons of the application ###

self.buttonBox = QtWidgets.QDialogButtonBox(QtCore.Qt.Vertical)
self.buttonBox.addButton(drawButton,
QtWidgets.QDialogButtonBox.ActionRole)
self.buttonBox.addButton(clearButton,
QtWidgets.QDialogButtonBox.ActionRole)
self.buttonBox.addButton(save, QtWidgets.QDialogButtonBox.ActionRole)
self.buttonBox.addButton(closedfigure, QtWidgets.QDialogButtonBox.ActionRole)

#### Layout for the window ###

# Layout for the window
self.makeWindowLayout(self.buttonBox)
self.setImage("resources/graph.png")

def makeInputLayout(self):
""" Makes the layout of the input area of the window which
contains the coordinate inputs and some other widgets"""

# Layouts for the window
text = 'Extra Info \N{Black Down-Pointing Triangle}'
self.inputLayout = QtWidgets.QFormLayout()
self.coordLayout = QtWidgets.QFormLayout()
self.scrollArea = QtWidgets.QScrollArea()

# WIdgets which will be added to the layout of the window
self.widget = QtWidgets.QWidget()
self.str = QtWidgets.QLabel('Geometric Figure:')
self.shapeName = QtWidgets.QLabel('Line')
self.extraInfo = QtWidgets.QPushButton(text, clicked=self.info)
self.extraInfo.setToolTip(('Show extra information '
'for the line or shape'))

# Adding the widgets to the layout of the window
self.shapeInfo = ExtraInfo()
self.widget.setLayout(self.coordLayout)
self.inputLayout.addRow(self.str, self.shapeName)
Expand All @@ -95,32 +101,25 @@ def makeInputLayout(self):
self.scrollArea.setWidgetResizable(True)
self.inputLayout.addRow(self.scrollArea)

def makeErrorDialog(self):
imageObj = QtGui.QImage('resources/error_symbol.ico')
caption = self.tr('Graph has to be drawn before saving')
image = QtWidgets.QLabel()
image.setPixmap(QtGui.QPixmap().fromImage(imageObj))
label = QtWidgets.QLabel(caption)
errorLayout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.LeftToRight)
errorLayout.addWidget(image)
errorLayout.addWidget(label)
self.errorSaving.setLayout(errorLayout)
self.errorSaving.setModal(True)

def makeWindowLayout(self, buttonBox):
'''Make the layout of the window'''
'''Makes the layout of the window'''

self.makeErrorDialog()
self.pointinput = QtWidgets.QFormLayout()

# The primary inputs for the coordinates of the lines
input1 = PointInput('Point1', self.points[0][0], self.points[0][1])
input2 = PointInput("Point2", self.points[1][0], self.points[1][1])

# The layout area of the input
layout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.LeftToRight)
addButton = QtWidgets.QPushButton(self.tr('+'), clicked=self.addPoint)
addButton.setToolTip('Add a new point for drawing shapes')
self.addButton = QtWidgets.QPushButton(self.tr('+'), clicked=self.addPoint)
self.addButton.setToolTip('Add a new point for drawing shapes')

# The layout area for the main window
self.windowLayout = layout
self.windowLayout.addWidget(self.image)
self.makeInputLayout()
self.coordLayout.addRow(addButton)
self.coordLayout.addRow(self.addButton)
self.coordLayout.addRow(input1)
self.coordLayout.addRow(input2)
self.windowLayout.addLayout(self.inputLayout)
Expand All @@ -142,8 +141,7 @@ def draw(self):
int(self.y_coord1.text()))
self.p2 = geometry.Point(int(self.x_coord2.text()),
int(self.y_coord2.text()))
self.draw_call = True
self.image.repaint()
geometry.plot(self, self.buttonBox.buttons()[3].isChecked())

def clear(self):
'''Not to be called by the program
Expand All @@ -153,24 +151,22 @@ def clear(self):
for i in self.points:
i[0].setText('0')
i[1].setText('0')
self.image.setPixmap("resources/graph.png")

self.setImage("resources/graph.png")

def save(self):
if not self.beingTested:
if hasattr(self, 'graph1'):
caption = self.tr('Choose a filename for saving the graph')
currentDT = datetime.datetime.now()
currentTime = currentDT.strftime("%H:%M:%S")
defFilename = self.fileDir + "graph-" + currentTime + ".png"
self.dialog = QFileDialog()
filename = self.dialog.getSaveFileName(self,
caption,
abspath('./untitled.png'),
self.tr('Images (*.png)'))
self.name = filename[0] if len(filename[0]) > 1 else defFilename
self.image.grab().toImage().save(self.name, "PNG")
else:
self.errorSaving.show()
caption = self.tr('Choose a filename for saving the graph')
currentDT = datetime.datetime.now()
currentTime = currentDT.strftime("%H:%M:%S")
defFilename = self.fileDir + "graph-" + currentTime + ".png"
self.dialog = QFileDialog()
filename = self.dialog.getSaveFileName(self,
caption,
abspath('./untitled.png'),
self.tr('Images (*.png)'))
self.name = filename[0] if len(filename[0]) > 1 else defFilename
self.image.grab().toImage().save(self.name, "PNG")
else:
self.defFilename = str(self.fileDir) + ("/img.png")
self.image.grab().toImage().save(str(self.defFilename), "PNG")
Expand All @@ -184,41 +180,46 @@ def check(self):
def setSaveFiledir(self, filedir):
self.fileDir = filedir

def paintEvent(self, e):
graph1 = QtGui.QImage()
if self.draw_call:
graph1.load("resources/graph.png")
self.draw_call = False
pen = QtGui.QPen(QtCore.Qt.black, 5, QtCore.Qt.SolidLine)
p = QtGui.QPainter()
p.begin(graph1)
p.setPen(pen)
geometry.plot(p, self.points)
p.end()
self.shapeInfo.updateInfo(self.points,
self.shapeName,
self.pointNum)
self.image.setPixmap(QtGui.QPixmap().fromImage(graph1))

def addPoint(self):
# Name of the shape
shapes = {
3: 'Triangle' if self.buttonBox.buttons()[3].isChecked() else 'Angle',
4: 'Quadrilateral' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
5: 'Pentagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
6: 'Hexagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
7: 'Septagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
8: 'Octagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
9: 'Enneagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
10: 'Decagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon'
}

# Input boxes for the points which are to be added
x1 = NumInput()
y1 = NumInput()

# Extend the points variable to include the new points
self.points.append([])
index = len(self.points) - 1
self.points[index].extend([x1, y1])
self.input = PointInput('Point' + str(self.pointNum),
input = PointInput('Point' + str(self.pointNum),
self.points[index][0],
self.points[index][1])
self.coordLayout.insertRow(self.coordLayout.rowCount(), self.input)

self.coordLayout.insertRow(self.coordLayout.rowCount(), input)
self.shapeInfo.str1.setText('Length of the sides:')
self.shapeInfo.distance.setStyleSheet('background:solid #F2F3f4')
self.pointNum += 1
self.shapeName.setText(shapes.get(index + 1,
('Undefined shape with {} number of '
'sides').format(index + 1)))
self.shapeInfo.distance.setText("Open")

def info(self):
"""
Show extra info/facts about the shape that has been drawn.
It will be shown only if the shape is a closed figure.
"""

if not self.pressedOnce:
self.extraInfo.setText('Extra Info \N{Black Up-Pointing Triangle}')
self.shapeInfo.show()
Expand All @@ -229,62 +230,27 @@ def info(self):
self.extraInfo.setText(('Extra Info'
'\N{Black Down-Pointing Triangle}'))

def dist(self):
x0 = int(self.points[0][0].text())
y0 = int(self.points[0][1].text())
x3 = int(self.points[1][0].text())
y3 = int(self.points[1][1].text())
x1 = x0 if x0 >= x3 else x3
y1 = y0 if y0 >= y3 else y3
x2 = x0 if x0 < x3 else x3
y2 = y0 if y0 < y3 else y3
if self.shapeName.text() == 'Line':
dist = math.sqrt(((x1 - x2) ** 2) + ((y1 - y2) ** 2))
else:
dist = 'N/A'
return dist if isinstance(dist, str) else f'{dist:.2f}'

def sumAngle(self):
sides = len(self.points)
sumOfAngles = (sides - 2) * 180
return str(sumOfAngles)

def sides(self):
if self.shapeName.text() == 'Line':
sides = str(1)
else:
sides = str(len(self.points))
return sides

def shapeType(self):
dist = []
try:
for i in range(0, len(self.points)):
x0 = int(self.points[i][0].text())
y0 = int(self.points[i][1].text())
x3 = int(self.points[i + 1][0].text())
y3 = int(self.points[i + 1][1].text())
x1 = x0 if x0 >= x3 else x3
y1 = y0 if y0 >= y3 else y3
x2 = x0 if x0 < x3 else x3
y2 = y0 if y0 < y3 else y3
distance = math.sqrt(((x1 - x2) ** 2) + ((y1 - y2) ** 2))
dist.append(distance)
except IndexError:
x0 = int(self.points[-1][0].text())
y0 = int(self.points[-1][1].text())
x3 = int(self.points[0][0].text())
y3 = int(self.points[0][1].text())
x1 = x0 if x0 >= x3 else x3
y1 = y0 if y0 >= y3 else y3
x2 = x0 if x0 < x3 else x3
y2 = y0 if y0 < y3 else y3
distance = math.sqrt(((x1 - x2) ** 2) + ((y1 - y2) ** 2))
dist.append(distance)
return 'Regular' if len(set(dist)) == 1 else 'Irregular'

def closeEvent(self, e):
if hasattr(self.shapeInfo, 'sidesLength'):
self.shapeInfo.sidesLength.close()
else:
e.accept()

def shapeNameChange(self, e):
if len(self.points) == 2:
pass
else:
shapes = {
3: 'Triangle' if self.buttonBox.buttons()[3].isChecked() else 'Angle',
4: 'Quadrilateral' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
5: 'Pentagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
6: 'Hexagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
7: 'Septagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
8: 'Octagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
9: 'Enneagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon',
10: 'Decagon' if self.buttonBox.buttons()[3].isChecked() else 'Open Polygon'
}
index = len(self.points) - 1
self.shapeName.setText(shapes.get(index + 1,
('Undefined shape with {} number of '
'sides').format(index + 1)))
Loading

0 comments on commit 8605277

Please sign in to comment.