1#!/usr/local/bin/python3.8 2 3import xasy2asy as x2a 4import numpy as np 5import math 6import PyQt5.QtCore as Qc 7import PyQt5.QtGui as Qg 8 9 10class PrimitiveShape: 11 # The magic number. 12 # see https://www.desmos.com/calculator/lw6j7khikj for unitcircle 13 # optimal_ctl_pt = 0.5447 14 15 @staticmethod 16 def pos_to_tuple(pos): 17 if isinstance(pos, tuple) or isinstance(pos, np.ndarray): 18 return pos 19 elif isinstance(pos, Qc.QPoint) or isinstance(pos, Qc.QPointF): 20 return pos.x(), pos.y() 21 else: 22 raise TypeError("Position must be a valid type!") 23 24 @staticmethod 25 def euclideanNorm(p1, p2): 26 x1, y1 = PrimitiveShape.pos_to_tuple(p1) 27 x2, y2 = PrimitiveShape.pos_to_tuple(p2) 28 29 normSq = ((x1 - x2) ** 2) + ((y1 - y2) ** 2) 30 return math.sqrt(normSq) 31 32 @classmethod 33 def circle(cls, position, radius): 34 pos_x, pos_y = PrimitiveShape.pos_to_tuple(position) 35 newCircle = x2a.asyPath() 36 ptsList = [(pos_x + radius, pos_y), (pos_x, pos_y + radius), (pos_x - radius, pos_y), (pos_x, pos_y - radius), 37 'cycle'] 38 # cycle doesn't work for now. 39 lkList = ['..', '..', '..', '..'] 40 newCircle.initFromNodeList(ptsList, lkList) 41 return newCircle 42 43 @classmethod 44 def inscribedRegPolygon(cls, sides, position, radius, starting_rad, qpoly=False): 45 pos_x, pos_y = PrimitiveShape.pos_to_tuple(position) 46 lkList = ['--'] * sides 47 ptsList = [] 48 for ang in np.linspace(starting_rad, starting_rad + math.tau, sides, endpoint=False): 49 ptsList.append((pos_x + radius * math.cos(ang), pos_y + radius * math.sin(ang))) 50 51 if qpoly: 52 ptsList.append((pos_x + radius * math.cos(starting_rad), pos_y + radius * math.sin(starting_rad))) 53 qpoints = [Qc.QPointF(x, y) for (x, y) in ptsList] 54 return Qg.QPolygonF(qpoints) 55 else: 56 ptsList.append('cycle') 57 newPoly = x2a.asyPath() 58 newPoly.initFromNodeList(ptsList, lkList) 59 return newPoly 60 61 @classmethod 62 def exscribedRegPolygon(cls, sides, position, length, starting_rad, qpoly=False): 63 ang = math.tau/sides 64 # see notes 65 adjusted_radius = length / math.cos(ang/2) 66 return cls.inscribedRegPolygon(sides, position, adjusted_radius, starting_rad - ang/2, qpoly) 67