#!/usr/bin/env python3 import xasy2asy as xasy2asy import numpy as numpy import math import PyQt5.QtCore as QtCore import PyQt5.QtGui as QtGui class PrimitiveShape: # The magic number. # see https://www.desmos.com/calculator/lw6j7khikj for unitcircle # optimal_ctl_pt = 0.5447 @staticmethod def pos_to_tuple(pos): if isinstance(pos, tuple) or isinstance(pos, numpy.ndarray): return pos elif isinstance(pos, QtCore.QPoint) or isinstance(pos, QtCore.QPointF): return pos.x(), pos.y() else: raise TypeError("Position must be a valid type!") @staticmethod def euclideanNorm(p1, p2): x1, y1 = PrimitiveShape.pos_to_tuple(p1) x2, y2 = PrimitiveShape.pos_to_tuple(p2) normSq = ((x1 - x2) ** 2) + ((y1 - y2) ** 2) return math.sqrt(normSq) @classmethod def circle(cls, position, radius): pos_x, pos_y = PrimitiveShape.pos_to_tuple(position) newCircle = xasy2asy.asyPath() ptsList = [(pos_x + radius, pos_y), (pos_x, pos_y + radius), (pos_x - radius, pos_y), (pos_x, pos_y - radius), 'cycle'] # cycle doesn't work for now. lkList = ['..', '..', '..', '..'] newCircle.initFromNodeList(ptsList, lkList) return newCircle @classmethod def inscribedRegPolygon(cls, sides, position, radius, starting_rad, qpoly=False): pos_x, pos_y = PrimitiveShape.pos_to_tuple(position) lkList = ['--'] * sides ptsList = [] for ang in numpy.linspace(starting_rad, starting_rad + math.tau, sides, endpoint=False): ptsList.append((pos_x + radius * math.cos(ang), pos_y + radius * math.sin(ang))) if qpoly: ptsList.append((pos_x + radius * math.cos(starting_rad), pos_y + radius * math.sin(starting_rad))) qpoints = [QtCore.QPointF(x, y) for (x, y) in ptsList] return QtGui.QPolygonF(qpoints) else: ptsList.append('cycle') newPoly = xasy2asy.asyPath() newPoly.initFromNodeList(ptsList, lkList) return newPoly @classmethod def exscribedRegPolygon(cls, sides, position, length, starting_rad, qpoly=False): ang = math.tau/sides # see notes adjusted_radius = length / math.cos(ang/2) return cls.inscribedRegPolygon(sides, position, adjusted_radius, starting_rad - ang/2, qpoly)