# Ryan Martin
# macid: abcd123
# student number: #######
# February 23, 2012
#
#
# This is a solution for Major Assignment 5 (Lab 11) on Wednesday.

from math import sqrt, acos 

class ConvexPolygon:

    def __init__(self, vertices):
        self.vertices = vertices

    def getVertices(self):
        #The [:] notation makes a copy, so we avoid aliasing issues
        return self.vertices[:]

    def setVertex(self, i, x, y):
        self.vertices[i][0] = float(x)
        self.vertices[i][1] = float(y)

    def getLength(self, i, j):
        v = self.getVertices()
        return sqrt((v[i][0] - v[j][0])**2 + (v[i][1] - v[j][1])**2)
    
    def getInteriorAngle(self, i):
        i = (i + 1) % len(self.getVertices()) - 1
        a = self.getLength(i, i+1)
        b = self.getLength(i-1, i)
        c = self.getLength(i-1, i+1)
        return acos((a**2 + b**2 - c**2)/(2.0*a*b))
    
def isRegularPolygon(p):
    firstLen = p.getLength(-1,0)
    firstAngle = p.getInteriorAngle(-1)
    for i in range(len(p.getVertices())-1):
        if p.getLength(i, i+1) != firstLen:
            return False
        if p.getInteriorAngle(i) != firstAngle:
            return False

    return True

'''
Design Question

An accessor, or "get" method, retrieves information
from a class, while a mutator, or "set" method, 
changes information within the class. 

This class contains 3 accessor methods, and 1
mutator method (setVertex). Though it can perhaps be argued
that getLength and getInteriorAngle are not accessors 
in the sense that they simply return an internal class 
variable, they still return some form of internal 
information (and certainly do not change the class 
in any way).

'''
##Note: This format is used by our automated marking system.
##You will see that, for inputs, the function name is
##given with the corresponding inputs to that function
##listed right after it. AutoMarker uses the data that you see here
##Format: [funName, [arg1, arg2, ...]]
##OR: 
##[ConvexPolygon, [initArg1, initArg2, ...], classFunName, [arg1, arg2, ...]]
##
##If you need to pass an instance of a class, use a tuple:
##('clsName', [arg1, arg2])
##and the class will be created at runtime.
##
##
##If the expected output for a function is an instance of a testingClass,
##each get method of testingClass and the actual output class will be compared.

'''
Testing Plan

class Class_State_Change: #equivalent to a basic ConvexPolygon class
	def __init__(self, v):
		self.v = v
	
	def getVertices(self):
		return self.v
       
v = [[0.75,3.5],[2.5,2.75],[2.25,-0.5],[-0.75,-1.5],[-0.25,2.25]]
v2 = [[]]

V03 = {'test1': 
       {'inputs': ['ConvexPolygon', [v], 'setVertex', [1,2.0,3.0]],
       'outputs': [Class_State_Change([[0.75,3.5],[2.0,3.0],[2.25,-0.5],[-0.75,-1.5],[-0.25,2.25]])]},
       'test2':
       {'inputs': ['ConvexPolygon', [v], 'getLength', [2,3]],
       'outputs': [3.1622776601683795]},
       'test3':
       {'inputs': ['ConvexPolygon', [v], 'getInteriorAngle', [3]],
       'outputs': [1.1164942401015803]},
       'test4':
       {'inputs': ['isRegularPolygon', [('ConvexPolygon', [v])]],
       'outputs': [False]},
       'test5':
       {'inputs': ['isRegularPolygon', [('ConvexPolygon', [[[-1.25,-0.75],[-1.25,1.25],[0.75,1.25],[0.75,-0.75]]])]],
       'outputs': [True]}
       'test6':
       {'inputs': ['ConvexPolygon', [v2], 'setVertex', [0,1.0,3.0]],
       'outputs': [IndexError: list assignment index out of range]},}

'''

