from rdkit import Chem
import argparse
import math
import os
from sklearn.metrics import mean_squared_error, r2_score
from statistics import stdev

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Calculate the RMSD value for a molecular property.')
    parser.add_argument('--original', '-o', metavar='ORIGINAL', required=True, type=str, help='File with original property values. SDF or SMILES format.')
    parser.add_argument('--prediction', '-p', metavar='PREDICTION', required=True, type=str, help='File with predicted property values. SDF or SMILES format.')
    parser.add_argument('--optimized', '-q', metavar="OPTIMIZED", type=str, help="File with optimized property predictions. SDF or SMILES format.")
    parser.add_argument('-i', '--id', type=str, default="_Name", help="ID tag for files in SD format.")
    parser.add_argument('-l', '--logfile', type=str, default="evaluation_result.log")
    parser.add_argument('--label_predicted', type=str, required=True, help="Label of the prediction.")
    parser.add_argument('--label_optimized', type=str, required=True, help="Label of the optimized prediction.")

    parser.add_argument('property', metavar='Property', type=str, help='Property of interest (should be similar in both files.')
    args = parser.parse_args()

    original_dict = {}
    pred_dict = {}
    opti_dict = {}
    orig_ext = os.path.splitext(args.original)[-1].lower()
    pred_ext = os.path.splitext(args.prediction)[-1].lower()

    id_label = args.id

    # collect original values
    if orig_ext == ".sdf":
        original_mols = Chem.SDMolSupplier(args.original)
        for mol in original_mols:
            original_dict[mol.GetProp(id_label)] = float(mol.GetProp(args.property))
    else:
        for line in open(args.original, "r"):
            line_arr = line.split("\t")
            original_dict[line_arr[1]] = float(line_arr[2])

    # collect values predicted values
    no_deviation = False
    if pred_ext ==".sdf":
        pred_mols = Chem.SDMolSupplier(args.prediction)
        for mol in pred_mols:
            pred_dict[mol.GetProp(id_label)] = float(mol.GetProp(args.property))
    else:
        for line in open(args.prediction, "r"):
            line_arr = line.split("\t")
            pred_dict[line_arr[1]] = float(line_arr[2])

    if args.optimized:
        if os.path.splitext(args.optimized)[-1].lower() == ".sdf":
            pred_mols = Chem.SDMolSupplier(args.optimized)
            for mol in pred_mols:
                opti_dict[mol.GetProp(id_label)] = float(mol.GetProp(args.label_optimized))
        else:
            for line in open(args.prediction, "r"):
                line_arr = line.split("\t")
                pred_dict[line_arr[1]] = float(line_arr[2]) + float(line_arr[3])

    sum_sq = 0

    preds = []
    orgs = []
    optis_all = [] # including unoptimizable prediction values
    optis_only = []
    orgs_only = []
    unoptimizable_ids = []

    unopt_values = []
    unopt_values_for_ori = []

    pred_in_net = []
    pred_not_in_net = []

    for id in pred_dict.keys():
        preds.append(pred_dict[id])
        orgs.append(original_dict[id])
        diff = (pred_dict[id] - original_dict[id])
        if args.optimized:
            if id in opti_dict.keys():
                optis_only.append(opti_dict[id])
                orgs_only.append(original_dict[id])
                optis_all.append(opti_dict[id])
                pred_in_net.append(pred_dict[id])
            else:
                unoptimizable_ids.append(id)
                optis_all.append(pred_dict[id])

                unopt_values.append(pred_dict[id])
                unopt_values_for_ori.append(original_dict[id])

                pred_not_in_net.append(pred_dict[id])

    with open(args.logfile, "w") as f:
        stdDev_orig_all = stdev(orgs)
        stdDev_orig_only_in_net = stdev(orgs_only)
        stdDev_orig_only_not_in_net = stdev(unopt_values_for_ori)

        stdDev_opt_all = stdev(optis_all)
        stdDev_opt_only_in_net = stdev(optis_only)

        f.write("StdDevs:\n")
        f.write(f"original all values:              {stdDev_orig_all}\n")
        f.write(f"original only in net values:      {stdDev_orig_only_in_net}\n")
        f.write(f"original only NOT in net values:  {stdDev_orig_only_not_in_net}\n")

        f.write(f"optimized all values:             {stdDev_opt_all}\n")
        f.write(f"optimized only in net values:     {stdDev_opt_only_in_net}\n\n")

        f.write(f"                              Root Mean Square Deviation    R²        Num_of_Samples\n")
        f.write(f"Predictions(all):             {mean_squared_error(orgs, preds, squared=False):.6f}                      {r2_score(orgs, preds):.6f}  {len(orgs)}\n")
        f.write(f"Predictions(only in net):     {mean_squared_error(orgs_only, pred_in_net, squared=False):.6f}                      {r2_score(orgs_only, pred_in_net):.6f}  {len(orgs_only)}\n")
        f.write(f"Predictions(only NOT in net): {mean_squared_error(unopt_values_for_ori, pred_not_in_net, squared=False):.6f}                      {r2_score(unopt_values_for_ori, pred_not_in_net):.6f}  {len(unopt_values_for_ori)}\n\n")

        if len(optis_all) > 0:
            f.write(f"Optimized (all):              {mean_squared_error(orgs, optis_all, squared=False):.6f}                      {r2_score(orgs, optis_all):.6f}  {len(orgs)}\n")
            f.write(
                f"Optimized (only):             {mean_squared_error(orgs_only, optis_only, squared=False):.6f}                      {r2_score(orgs_only, optis_only):.6f}  {len(orgs_only)}\n\n")
        if len(unopt_values) > 0:
            f.write(f"Scores (un_opt):              {mean_squared_error(unopt_values_for_ori, unopt_values, squared=False):.6f}                      {r2_score(unopt_values_for_ori, unopt_values):.6f}  {len(unopt_values)}\n")
        f.write(f"\nUnoptimizable molecules (IDs) ({len(unoptimizable_ids)} mols):\n")
        for id in unoptimizable_ids:
            f.write(f"{id}\n")


# -*- coding: utf-8 -*-

import streamlit as st
from topics import TopicModel

import pandas as pd
import numpy as np
from scipy.optimize import linear_sum_assignment
import matplotlib.pyplot as plt

import base64

@st.cache(allow_output_mutation=True)
def load_corpus(url):
	return tm.load_corpus(url)

# check the cache if there is already a model for this url, stopwords and number_of_topics
@st.cache(allow_output_mutation=True, persist=True, show_spinner=False)
def lda_model(url, stopwords, number_of_topics):
	corpus = load_corpus(url)
	corpus.update_stopwords(stopwords)
	with st.spinner("Training the topic model for {} topics ...".format(number_of_topics)):
		print("*** Training the topic model: {}".format(number_of_topics))
		return lda_model_no_cache(corpus, number_of_topics)

def lda_model_no_cache(corpus, number_of_topics):
	if use_heuristic_alpha_value:
		return tm.fit(corpus, number_of_topics, alpha="talley", number_of_chunks=number_of_chunks)
	else:
		return tm.fit(corpus, number_of_topics, number_of_chunks=number_of_chunks)

# check the cache if there are already runs for this url, stopwords and number_of_topics
@st.cache(allow_output_mutation=True, persist=True, show_spinner=False)
def lda_model_runs(url, stopwords, number_of_topics, n=4):
	corpus = load_corpus(url)
	corpus.update_stopwords(stopwords)
	with st.spinner("Creating {} different topic models".format(n)):
		lda_models = [lda_model_no_cache(corpus, number_of_topics) for run in range(n)]
		return lda_models

def topic_alignment(n):
	lda_models = lda_model_runs(url, stopwords, number_of_topics, n=n)
	topics = pd.DataFrame([[" ".join([tw[0] for tw in lda.lda.show_topic(t, 10)]) for lda in lda_models]
		for t in range(number_of_topics)])
	diff = [lda_models[0].difference(lda_models[i]) for i in range(1, n)]
	matches = pd.DataFrame()
	matches[0] = range(number_of_topics)
	for i in range(1, n):
		_, cols = linear_sum_assignment(diff[i-1])
		matches[i] = cols
	return topics, matches, lda_models, diff

def highlight_topic(x, topic, matches, color="lightgreen"):
	color = "background-color: %s" % (color)
	df = pd.DataFrame('', x.index, x.columns)
	for run in range(len(x.columns)):
		df[run].loc[matches[run][topic]] = color
	return df

def topic_runs(lda_models, topic, matches):
	keywords = pd.DataFrame()
	weights = pd.DataFrame()
	documents = pd.DataFrame()
	for run in range(len(lda_models)):
		keywords[run] = [tw[0] for tw
			in lda_models[run].lda.show_topic(matches[run][topic], 10)]
		weights[run] = [tw[1] for tw
			in lda_models[run].lda.show_topic(matches[run][topic], 10)]
		# todo: while correct, this is inefficient as the DTM is recomputed for each run
		documents[run] = document_topics_matrix(lda_models[run])[matches[run][topic]]
	return lda_models, keywords, weights, documents

# done: once we pass weights, use the relative weights to assign colors
# relative weight = weight / lowest weight in top 10
# for all keywords that are repeated across topics, color them blue if all >= 2,
# green if some >= 2, and blue if all < 2
def highlight_repeated_keywords(keywords, weights):
	df = pd.DataFrame('', keywords.index, keywords.columns)
	num_runs, num_words = len(keywords.columns), len(keywords.index)
	# extract array from data frame
	# we transpose the array so that each row represents one run
	keywords = keywords.values.T
	weights = weights.values.T
	repeated_keywords = []
	for keyword in keywords[0]:
		i = 0
		for run in range(1, num_runs):
			if keyword in keywords[run]:
				i = i + 1
		# print("keyword {} occurs {} times".format(keyword, i))
		if i == num_runs - 1:
			repeated_keywords.append(keyword)
	color = keyword_color(repeated_keywords, num_runs, num_words, keywords, weights)
	for j in range(num_runs):
		for i in range(num_words):
			if keywords[j,i] in repeated_keywords:
				df[j].loc[i] = "background-color: light%s" % (color[keywords[j,i]])
	return df

def keyword_color(repeated_keywords, num_runs, num_words, keywords, weights):
	color = {}
	for keyword in repeated_keywords:
		color[keyword] = None
	for j in range(num_runs):
		for i in range(num_words):
			if keywords[j,i] in repeated_keywords:
				ratio = weights[j,i]/weights[j,num_words-1]
				if ratio >= 2.0:
					if color[keywords[j,i]] is None:
						color[keywords[j,i]] = 'yellow'
					elif color[keywords[j,i]] == 'blue':
						color[keywords[j,i]] = 'green'
				else:
					if color[keywords[j,i]] is None:
						color[keywords[j,i]] = 'blue'
					elif color[keywords[j,i]] == 'yellow':
						color[keywords[j,i]] = 'green'
	return color

def document_topics_matrix(lda):
	dtm = []
	for document_bow in corpus.bow():
		dtm.append(topics_sparse_to_full(lda.get_document_topics(document_bow)))
	return pd.DataFrame(dtm)

def topics_sparse_to_full(topics):
	topics_full = [0] * number_of_topics  # pythonic way of creating a list of zeros
	for topic, score in topics:
		topics_full[topic] = score
	return topics_full

def download_link_from_csv(csv, file_name, title="Download"):
	b64 = base64.b64encode(csv.encode()).decode()  # some strings <-> bytes conversions necessary here
	href = "{}".format(b64, file_name, title)
	st.markdown(href, unsafe_allow_html=True)

def download_link_from_html(html, file_name, title="Download"):
	b64 = base64.b64encode(html.encode()).decode()  # some strings <-> bytes conversions necessary here
	href = "{}".format(b64, file_name, title)
	st.markdown(href, unsafe_allow_html=True)

st.sidebar.title("Topic Model Explorer")
tm = TopicModel()

url = st.sidebar.file_uploader("Corpus", type="csv")

stopwords = st.sidebar.text_area("Stopwords (one per line)")
update_stopwords = st.sidebar.button("Update stopwords")

if update_stopwords:
	if url is not None:
		corpus = load_corpus(url)
		corpus.update_stopwords(stopwords)

show_documents = st.sidebar.checkbox("Show documents", value=True)

if show_documents:
	st.header("Corpus")
	if url is not None:
		corpus = load_corpus(url)
		if('name' not in corpus.documents or 'content' not in corpus.documents):
			st.markdown('''
		The corpus must have a *name* and a *content* column.
			''')
		st.dataframe(corpus.documents)
		download_link_from_csv("\n".join(corpus.stopwords), "stopwords.txt",
			"Download stopwords")
	else:
		st.markdown("Please upload a corpus.")

number_of_topics = st.sidebar.slider("Number of topics", 1, 50, 10)
use_heuristic_alpha_value = st.sidebar.checkbox("Use heuristic value for alpha", value=False)
number_of_chunks = st.sidebar.slider("Number of chunks", 1, 100, 100)

show_runs = st.sidebar.checkbox("Compare topic model runs", value=False)

if show_runs:
	st.header("Topic Model Runs")
	topic_to_highlight = st.sidebar.selectbox("Highlight topic", range(number_of_topics), 0)
	show_runs_all_topics = st.sidebar.checkbox("Show all topics", value=True)
	if url is None:
		st.markdown("No corpus")
	elif show_runs_all_topics:
		topics, matches, lda_models, diff = topic_alignment(4)
		st.table(topics.style
			.apply(highlight_topic, topic=topic_to_highlight, matches=matches, axis=None))
		download_link_from_csv(topics.to_csv(index=False),
			"tm-{}-runs.csv".format(number_of_topics),
			title="Download topics as CSV")
	else:
		# todo: topic_alignment to return weights as well
		# then pass weights as argument to highlight_repeated_keywords
		topics, matches, lda_models, diff = topic_alignment(4)
		lda_models, keywords, weights, documents = topic_runs(lda_models, topic=topic_to_highlight, matches=matches)
		st.table(keywords.style
			.apply(highlight_repeated_keywords, weights=weights, axis=None))
		download_link_from_csv(keywords.to_csv(index=False),
			"tm-{}-{}-keywords.csv".format(number_of_topics, topic_to_highlight),
			title="Download keywords as CSV")
		download_link_from_html(keywords.style
			.apply(highlight_repeated_keywords, weights=weights, axis=None)
			.render(),
			"tm-{}-{}-keywords.html".format(number_of_topics, topic_to_highlight),
			title="Download keywords as HTML (with colors)")
		st.table(weights)
		download_link_from_csv(keywords.to_csv(index=False),
			"tm-{}-{}-weights.csv".format(number_of_topics, topic_to_highlight),
			title="Download weights as CSV")
		st.dataframe(documents)


import os

import numpy as np
import torch
import torch.nn as nn

class Generator(nn.Module):
    def __init__(self, latent_dim, img_shape):
        super().__init__()
        self.img_shape = img_shape
        self.label_embed = nn.Embedding(10, 10)

        def block(in_feat, out_feat, normalize=True):
            layers = [nn.Linear(in_feat, out_feat)]
            if normalize:
                layers.append(nn.BatchNorm1d(out_feat, 0.8))
            layers.append(nn.LeakyReLU(0.2, inplace=True))
            return layers

        self.model = nn.Sequential(
            *block(latent_dim+10, 128, normalize=False),
            *block(128, 256),
            *block(256, 512),
            *block(512, 1024),
            nn.Linear(1024, int(np.prod(img_shape))),
            nn.Tanh(),
        )

    def forward(self, z, labels):
        c = self.label_embed(labels)
        z = torch.cat([z, c], dim=1)

        img = self.model(z)
        img = img.view(img.shape[0], *self.img_shape)
        return img

class Discriminator(nn.Module):
    def __init__(self, img_shape):
        super().__init__()

        self.label_embed = nn.Embedding(10, 10)

        self.model = nn.Sequential(
            nn.Linear(int(np.prod(img_shape))+10, 512),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Linear(512, 256),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Linear(256, 1),
            nn.Sigmoid(),
        )

    def forward(self, img, labels):
        img_flat = img.view(img.size(0), -1)
        c = self.label_embed(labels)
        x = torch.cat([img_flat, c], dim=1)
        validity = self.model(x)
        return validity


from PyQt5.QtCore import QModelIndex, pyqtSignal, pyqtSlot, QVariant, QFile, QByteArray, QBuffer, QIODevice, QSize, \
    QItemSelectionModel, QItemSelection
from PyQt5.QtGui import QPixmap, QFont, QIcon
from PyQt5.QtSql import QSqlQuery
from PyQt5.QtWidgets import QWidget, QApplication, QLabel, QDialog, QMessageBox

from TreeModel import TreeModel
from inputdialog import InputDialog
from connect1 import Connect1
from newForm import *

class Widget2(QWidget):
    def __init__(self):
        super().__init__()
        self.db = None
        self.setWindowModality(QtCore.Qt.ApplicationModal)
        self.setFixedSize(600, 400)
        self.setWindowTitle("Лейман М.А.")
        label = QLabel(self)
        label.move(25, 25)
        label.setFixedSize(550, 350)
        label.setStyleSheet('background-color: rgb(180, 190, 200)')
        label.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        label.setFont(QFont('Arial', 15))
        label.setWordWrap(True)
        label.setText('Тестовая программа\n \nПостроение из базы данных иерархического списка\n в виде дерева,'
                      'с возможностью редактирования\n и добавления дочерних элементов. \n \n \n '
                      ' выполнил: Лейман М.А.\n тел: +79613224543\n email: makc.mon@mail.ru')
        self.setWindowFlags(QtCore.Qt.Dialog)  # делает окно несворачиваемым

class Widget1(QtWidgets.QWidget):
    valueChangedSignal = pyqtSignal(list)
    valueInsertSignal = pyqtSignal(list)

    def __init__(self, parent):
        QtWidgets.QWidget.__init__(self, parent)
        self.idRowNew = None  # id новой (вставляемой) строки
        self.__iDialog = None
        self.w = None
        self.y = None
        self.ui = Ui_Widget()
        pixmap = QPixmap(":/img2.png")  # установка эмблеммы в окно
        self.ui.setupUi(self)
        self.ui.label_2.setPixmap(pixmap)
        self.ui.label.setPixmap(pixmap)
        self.ui.treeView.setAttribute(QtCore.Qt.WA_StyledBackground, True)
        self.ui.treeView.setStyleSheet('background-color: rgb(170, 190,195)')  # установка фона для окна дерева
        self.ui.button.setToolTip("
Нажми меня
")
        self.ui.button.setStyleSheet("background-color : rgb(10, 120, 10)")
        self.db = Connect1("task")
        cursor = self.db.connect_to_data_base
        treemodel = TreeModel()
        self.ui.treeView.setModel(treemodel)
        self.ui.button.clicked.connect(self.window_open)  # открывает окно "О программе" +
        self.ui.delRow.clicked.connect(self.removeRowTree)  # удаляет строку (узел) с дочерними строками +
        self.ui.modifi.clicked.connect(self.modifiRow)  # изменяет данные строки (узла) -
        self.ui.addRow.clicked.connect(self.insertChildTree)  # Добавляет строку (Узел) -
        self.ui.treeView.selectionModel().selectionChanged[QItemSelection, QItemSelection].connect(self.updateActions)
        self.ui.treeView.selectionModel().currentRowChanged[QModelIndex, QModelIndex].connect(self.slotCurrentPic)
        self.valueChangedSignal[list].connect(self.editDataBase)    # Изменяет выбранный элемент  в БАЗЕ
        self.valueInsertSignal[list].connect(self.insertDataBase)  # вставляем  новые данные в БАЗУ

        self.ui.treeView.setColumnHidden(2, True) # делает невидимым столбцы 2,3,4
        self.ui.treeView.setColumnHidden(3, True)
        self.ui.treeView.setColumnHidden(4, True)
        header = self.ui.treeView.header()
        header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
        header.setSectionResizeMode(2, QtWidgets.QHeaderView.Fixed)
        header.setSectionResizeMode(3, QtWidgets.QHeaderView.Fixed)
        header.setSectionResizeMode(4, QtWidgets.QHeaderView.Fixed)
        header.setStretchLastSection(False)
        self.updateActions()

    def window_open(self):
        self.w = Widget2()
        self.w.show()
        # self.hide()

    def closeEvent(self, event):
        self.db.close_db()
        for window in QApplication.topLevelWidgets():
            window.close()

    def slotCurrentPic(self, index: QModelIndex):

        yurModel = self.ui.treeView.model()
        item = yurModel.getItem(index)
        pix = item.data(1)
        if not isinstance(pix, QByteArray):
            # sss = QByteArray(item.data(1).encode())
            sss = ":/img2.png"
            outPixmap = QPixmap(sss)
            pixmap = outPixmap.scaledToWidth(200)
        else:
            sss = pix
            outPixmap = QPixmap()
            outPixmap.loadFromData(sss)
            dd = outPixmap.width()
            pixmap = outPixmap.scaledToWidth(200)
        self.ui.label.setPixmap(pixmap)

    @pyqtSlot()
    def insertChildTree(self):
        pInputDialog = InputDialog()
        if pInputDialog.flag:
            name = pInputDialog.name()  # вводим данные
            image = pInputDialog.image()
            state = pInputDialog.state()
            var = pInputDialog.destroyed
            index = self.ui.treeView.selectionModel().currentIndex()  # Получаем модельный индекс элемента
            model = self.ui.treeView.model()  #  получаем модель дерева
            colCount = model.columnCount(index)
            itemParent = model.getItem(index)  # получаем выбранный элемент, он становится родителем вставляемого элемента
            idParentRow = int(itemParent.data(2))  # получаем id выбранной строки, становится id_parent для вставляемого элемента
            newValue = list()
            newValue.append(name)
            newValue.append(image)
            newValue.append(state)
            newValue.append(idParentRow)
            self.valueInsertSignal.emit(newValue)  # отправляем сигнал на запись данных в БД
            newValue.clear()
            query2 = QSqlQuery()  # получаем изображение
            query2.prepare("SELECT * FROM  hierarhy  WHERE id =?;")
            query2.addBindValue(self.idRowNew)
            query2.exec()
            query2.next()
            image2 = query2.value(3)
            query2.clear()
            newValue.append(name)
            newValue.append(image2)
            newValue.append(self.idRowNew)
            newValue.append(idParentRow)
            newValue.append(state)
            rowNew = model.rowCount(index)
            if not model.insertRow(rowNew, index):
                return
            dictRole = (0, 1, 0, 0, 0)
            for column in range(colCount):
                indexChild = model.index(rowNew, column, index)  # индекс  вставляемого элемента в модели
                model.setData(indexChild, newValue[column], dictRole[column])      # вставляем данные  в столбец модели по индексу
            self.ui.treeView.selectionModel().reset()
            self.updateActions()

    def updateActions(self):
        hasSelection = not self.ui.treeView.selectionModel().selection().isEmpty()
        self.ui.delRow.setEnabled(hasSelection)
        self.ui.modifi.setEnabled(hasSelection)

    @pyqtSlot()
    def modifiRow(self):
        pInputDialog = InputDialog()
        if pInputDialog.flag:
            name = pInputDialog.name()  # вводим данные
            image = pInputDialog.image()
            state = pInputDialog.state()
            var = pInputDialog.destroyed
            index = self.ui.treeView.selectionModel().currentIndex()  # модельный индекс элемента
            model = self.ui.treeView.model()
            item2 = model.getItem(index)     # выбранный элемент
            rowItem = item2.rowNumber()        # номер строки элемента  в родительском узле
            idRow = int(item2.data(2))      #  id выбранной строки
            idRowParent = int(item2.data(3))  #  id_parent выбраной строки
            parent = model.parent(index)      # индекс родителя
            newValue = list()
            newValue.append(name)
            newValue.append(image)
            newValue.append(state)
            newValue.append(idRow)
            self.valueChangedSignal.emit(newValue)  # отправляем сигнал на запись данных в БД
            newValue.clear()
            query2 = QSqlQuery()  # получаем изображение
            query2.prepare("SELECT * FROM  hierarhy  WHERE id =?;")
            query2.addBindValue(idRow)
            query2.exec()
            query2.next()
            image2 = query2.value(3)
            query2.clear()
            newValue.append(name)
            newValue.append(image2)
            newValue.append(idRow)
            newValue.append(idRowParent)
            newValue.append(state)
            model.beginResetModel1()  # Изменяем данные в строке
            colCount = model.columnCount(index)
            dictRole = (0, 1, 0, 0, 0)
            for column in range(colCount):
                indexInsert = model.index(rowItem, column, parent)  # УЗНАТЬ СТРОКУ Изменяемого (ТЕКУЩЕГО) ЭЛЕМЕНТА
                model.setData(indexInsert, newValue[column], dictRole[column])
            model.endResetModel1()
            newValue.clear()
        self.updateActions()
        var = pInputDialog.destroyed

    def removeRowTree(self):
        """   удаляет строку со всеми зависимыми строками """
        model = self.ui.treeView.model()
        index = self.ui.treeView.selectionModel().currentIndex()  # Получаем модельный индекс выбранного элемента
        self.remoweItemRows(index, model)
        self.ui.treeView.selectionModel().reset()
        self.updateActions()

    def remoweItemRows(self, index: QModelIndex, model: TreeModel):  # удаляет элементы из списка детей
        item = model.getItem(index)
        childCountItem = item.childCount() # количество детей у элемента
        numRow = item.rowNumber()    #  номер строки элемента
        indexParent = model.parent(index) # индекс родителя элемента
        if childCountItem > 0:
            for numRowChild in range(childCountItem - 1, - 1, -1):
                indexChild = model.index(numRowChild, 0, index)
                self.remoweItemRows(indexChild, model)     #  каскадное удаление  потомков потомка
        idRow = int(item.data(2))  # получаем id строки
        if not model.hasChildren(index):  # если нет потомков, то удаляем узел
            query2 = QSqlQuery()
            query2.prepare("DELETE FROM  hierarhy  WHERE id =?;")
            query2.addBindValue(idRow)
            query2.exec()
            query2.clear()
        model.removeRow(numRow, indexParent)     #  Удаляем текущий узел после удаления  всех детей

    @pyqtSlot(list)
    def insertDataBase(self, newValue: list):
        """ вставляет новые данные в базу"""
        strName = str(newValue[0])
        if strName == '':
            return
        strImg1 = str(newValue[1])
        file = QFile(strImg1)  # создаем объект класса QFile
        dataImg = QByteArray()  # куда будем считывать данные
        # inBuffer = QBuffer(dataImg)
        if file.open(QIODevice.ReadOnly):  # Проверяем, возможно ли открыть наш файл для чтения
            dataImg = file.readAll()  # считываем данные
        query3 = QSqlQuery()
        query3.exec("INSERT INTO hierarhy (id_parent,name,image,state) VALUES (?, ?, ?, ?)")
        strIdParent = int(newValue[3])
        query3.addBindValue(strIdParent)
        query3.addBindValue(strName)
        query3.addBindValue(dataImg)
        strState = str(newValue[2])
        query3.addBindValue(strState)
        query3.exec()
        self.idRowNew = int(query3.lastInsertId())
        query3.clear()

    @pyqtSlot(list)
    def editDataBase(self, newValue: list):
        strName = str(newValue[0])
        if strName == '':
            return
        strImg1 = newValue[1]
        file = QFile(strImg1)  # создаем объект класса QFile
        dataImg = QByteArray()  # куда будем считывать данные
        if file.open(QIODevice.ReadOnly):  # Проверяем, возможно ли открыть наш файл для чтения
            dataImg = file.readAll()
        query3 = QSqlQuery()
        query3.prepare("UPDATE hierarhy SET name=?, image=?, state=? WHERE id =?;")
        strName = str(newValue[0])
        query3.addBindValue(strName)
        query3.addBindValue(dataImg)
        strState = str(newValue[2])
        query3.addBindValue(strState)
        idRow = int(newValue[3])
        query3.addBindValue(idRow)
        query3.exec()
        query3.next()
        if not query3.isActive():
            QMessageBox.warning(self, "Database Error", query3.lastError().text())


import unittest
from datetime import date, datetime

from constants import (
    STATUS_IN_PROGRESS,
    STATUS_COMPLETED,
    TASK_UPDATED,
    PRIORITY_HIGH,
    PRIORITY_MEDIUM,
    PRIORITY_LOW,
    TASK1,
    TASK2,
    TASK3
)
from main import app, bd
from models.task_model import Task
from repository.task_repository import TaskRepository
from service.task_service import get_all_tasks, create_task, update_task, delete_task

class TaskServiceTestCase(unittest.TestCase):
    def setUp(self):
        app.testing = True
        app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
        self.app_context = app.app_context()
        self.app_context.push()
        bd.create_all()
        self.client = app.test_client()
        self.repository = TaskRepository()

    def tearDown(self):
        bd.session.remove()
        bd.drop_all()

    def test_get_all_tasks(self):
        task1 = Task(
            name=TASK1,
            priority=PRIORITY_HIGH,
            start_date=date.today(),
            planned_end_date=date.today(),
            actual_end_date=None,
            status=STATUS_IN_PROGRESS,
            project_id='1'
        )
        task2 = Task(
            name=TASK2,
            priority=PRIORITY_MEDIUM,
            start_date=date.today(),
            planned_end_date=date.today(),
            actual_end_date=None,
            status=STATUS_IN_PROGRESS,
            project_id='2'
        )
        task3 = Task(
            name=TASK3,
            priority=PRIORITY_LOW,
            start_date=date.today(),
            planned_end_date=date.today(),
            actual_end_date=None,
            status=STATUS_IN_PROGRESS,
            project_id='3'
        )

        self.repository.create(task1)
        self.repository.create(task2)
        self.repository.create(task3)

        tasks_project1 = get_all_tasks(task1.project_id)
        tasks_project2 = get_all_tasks(task2.project_id)
        tasks_project3 = get_all_tasks(task3.project_id)

        self.assertEqual(len(tasks_project1), 1)
        self.assertEqual(tasks_project1[0]['name'], TASK1)
        self.assertEqual(tasks_project1[0]['priority'], PRIORITY_HIGH)
        self.assertEqual(tasks_project1[0]['start_date'], date.today().strftime('%Y-%m-%d'))
        self.assertEqual(tasks_project1[0]['planned_end_date'], date.today().strftime('%Y-%m-%d'))
        self.assertIsNone(tasks_project1[0]['actual_end_date'])
        self.assertEqual(tasks_project1[0]['status'], STATUS_IN_PROGRESS)

        self.assertEqual(len(tasks_project2), 1)
        self.assertEqual(tasks_project2[0]['name'], TASK2)
        self.assertEqual(tasks_project2[0]['priority'], PRIORITY_MEDIUM)
        self.assertEqual(tasks_project2[0]['start_date'], date.today().strftime('%Y-%m-%d'))
        self.assertEqual(tasks_project2[0]['planned_end_date'], date.today().strftime('%Y-%m-%d'))
        self.assertIsNone(tasks_project2[0]['actual_end_date'])
        self.assertEqual(tasks_project2[0]['status'], STATUS_IN_PROGRESS)

        self.assertEqual(len(tasks_project3), 1)
        self.assertEqual(tasks_project3[0]['name'], TASK3)
        self.assertEqual(tasks_project3[0]['priority'], PRIORITY_LOW)
        self.assertEqual(tasks_project3[0]['start_date'], date.today().strftime('%Y-%m-%d'))
        self.assertEqual(tasks_project3[0]['planned_end_date'], date.today().strftime('%Y-%m-%d'))
        self.assertIsNone(tasks_project3[0]['actual_end_date'])
        self.assertEqual(tasks_project3[0]['status'], STATUS_IN_PROGRESS)

    def test_create_task(self):
        project_id = 1
        data = {
            'name': 'New Task',
            'priority': 'High',
            'status': 'In Progress',
            'planned_end_date': '2023-07-20'
        }

        create_task(project_id, data)
        task = self.repository.get_all()[0]

        self.assertIsNotNone(task.id)
        self.assertEqual(task.name, 'New Task')
        self.assertEqual(task.priority, 'High')
        self.assertEqual(task.start_date, date.today())
        self.assertEqual(task.planned_end_date, datetime.strptime(data['planned_end_date'], '%Y-%m-%d').date())
        self.assertIsNone(task.actual_end_date)
        self.assertEqual(task.status, 'In Progress')
        self.assertEqual(task.project_id, 1)

    def test_update_task(self):
        task = Task(
            name=TASK1,
            priority=PRIORITY_HIGH,
            start_date=date.today(),
            planned_end_date=date.today(),
            actual_end_date=None,
            status=STATUS_IN_PROGRESS
        )
        self.repository.create(task)

        data = {
            'name': TASK_UPDATED,
            'priority': PRIORITY_MEDIUM,
            'status': STATUS_COMPLETED
        }

        update_task(task.id, data)
        updated_task = self.repository.get_by_id(task.id)

        self.assertEqual(updated_task.name, TASK_UPDATED)
        self.assertEqual(updated_task.priority, PRIORITY_MEDIUM)
        self.assertEqual(updated_task.status, STATUS_COMPLETED)

    def test_delete_task(self):
        task_data = {
            'name': TASK1,
            'priority': PRIORITY_HIGH,
            'start_date': date.today(),
            'planned_end_date': date.today(),
            'actual_end_date': None,
            'status': STATUS_IN_PROGRESS
        }
        task = Task(**task_data)
        self.repository.create(task)
        task_id = task.id

        delete_task(task_id)
        deleted_task = self.repository.get_by_id(task_id)

        self.assertIsNone(deleted_task)

# def setUp(self):
#     app.testing = True
#     app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
#     self.app_context = app.app_context()
#     self.app_context.push()
#     bd.create_all()
#     self.client = app.test_client()
#     self.repository = TaskRepository()

#
# def tearDown(self):
#     bd.session.remove()
#     bd.drop_all()

if __name__ == '__main__':
    unittest.main()


import setuptools

with open("README.md", "r") as fh:
    long_description = fh.read()

setuptools.setup(
    name="visbeat",
    version="0.0.9",
    author="Abe Davis",
    author_email="everyonehasadance@gmail.com",
    description="Code for 'Visual Rhythm and Beat' SIGGRAPH 2018",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/abedavis/visbeat",
    project_urls={
        'Abe Davis': 'http://www.abedavis.com/',
        'Visual Rhythm and Beat': 'http://www.abedavis.com/visualbeat/',
        'Source': 'https://github.com/abedavis/visbeat',
        'Demo': 'http://www.abedavis.com/visualbeat/demo/',
    },
    install_requires=[
        'numpy',
        'scipy',
        'bs4',
        'librosa',
        'imageio',
        'requests',
        'moviepy',
        'termcolor',
        'youtube-dl',
        'matplotlib',
    ],
    scripts=['bin/dancefer'],
    packages=setuptools.find_packages(exclude=['contrib', 'docs', 'tests*']),
    include_package_data=True,
    classifiers=[
        "Programming Language :: Python :: 2.7",
        "Operating System :: OS Independent",
    ],
)


#!/usr/bin/env python

"""Visualisation.py: Visualise data from simulation"""

__author__ = "Murray Ireland"
__email__ = "murray@craftprospect.com"
__date__ = "22/10/2018"
__copyright__ = "Copyright 2017 Craft Prospect Ltd"
__licence___ = ""

import vtk
import numpy as np
from math import tan, sin, cos, atan, pi
# import msvcrt
import sys, os
import platform
from datetime import datetime
from time import sleep

if platform.system() == "Windows":
    from win32api import GetSystemMetrics
    screen_size = (GetSystemMetrics(0), GetSystemMetrics(1))
elif platform.system() == "Linux":
    try:
        import tkinter as tk
    except ImportError:
        import Tkinter as tk

    root = tk.Tk()
    screen_size = (root.winfo_screenwidth(), root.winfo_screenheight())

# Get current and base directories
cur_dir = os.path.dirname(os.path.realpath(__file__))
if "\\" in cur_dir:
    base_dir = "/".join(cur_dir.split("\\"))
else:
    base_dir = cur_dir

class Visualisation(object):
    """Class for visualisation object"""

    # Scale time
    TIME_SCALE = 1

    # Turn text overlay on/off
    SHOW_TEXT = True

    # Full-screen and window scaling
    FULL_SCREEN = True
    WIN_H_SCALE = 1.
    WIN_V_SCALE = 1.
    TEXT_SCALE = 1.

    # Use lower resolution textures where appropriate
    USE_SMALL_IMAGES = False

    # Scale entire animation for troubleshooting
    ANI_SCALE = 1.

    # Scale satellite up for better visibility
    SAT_SCALE = 500.   # Breaks if too small

    # Colours
    COLOUR_BG = (0, 0, 0)
    COLOUR_FONT = (0.871, 0.246, 0.246)

    # Set solar panel angles [deg]
    PANEL_ANGLE = 10

    # Tile size for Earth textures [m]
    TILE_SIZE = (177390, 183360)

    # Anchor settings
    ANCHOR = {
        "SW": (0, 0),
        "NW": (0, 2),
        "NE": (2, 2),
        "SE": (2, 0),
        "N": (1, 2),
        "E": (2, 1),
        "S": (1, 0),
        "W": (0, 1),
        "C": (1, 1)
    }

    def __init__(self, PROPS, data):
        """Class constructor"""

        # Screen size and aspect ratio
        self.SCREEN_SIZE = (screen_size[0], screen_size[1])
        self.SCREEN_AR = float(self.SCREEN_SIZE[0])/float(self.SCREEN_SIZE[1])

        # Initialise property dictionaries
        self.SAT_PROPS = PROPS["Sat"]
        self.CAM_PROPS = PROPS["Camera"]
        self.IMG_PROPS = PROPS["Imagery"]
        self.LSR_POS = PROPS["Laser"]
        self.EARTH_PROPS = PROPS["Earth"]

        # Initialise simulation data
        self.DATA = data

        # Initialise imagery
        self.IMG_PROPS["Texture size"] = (
            self.IMG_PROPS["Size"]["full"][0]*self.IMG_PROPS["Res"]["full"],
            self.IMG_PROPS["Size"]["full"][1]*self.IMG_PROPS["Res"]["full"]
        )

        # Initialise index
        self.index = 0

        # Initialise render window and interactor
        self.renWin, self.iren = self.init_renderer()
        self.ren = {}

        # Create scenes
        self.actors, self.cameras, self.text, self.lights = self.create_scenes()

        for key in self.lights.keys():
            for light in self.lights[key]:
                self.ren[key].AddLight(light)

        # Render scenes
        self.iren.Initialize()
        self.renWin.Render()

        # Initialise time
        now = datetime.now()
        self.init_time = [now.hour, now.minute, now.second]

        # Create timer event
        self.iren.AddObserver("TimerEvent", self.execute)
        timerId = self.iren.CreateRepeatingTimer(int(1000*self.DATA["Time step"]))

        # Start interactor and timer
        self.iren.Start()

        # Stop timer?
        # self.movieWriter.End()

    def init_renderer(self):
        """Initialise render window and interactor"""

        # Initialise render window
        renWin = vtk.vtkRenderWindow()
        if self.FULL_SCREEN:
            renWin.FullScreenOn()
        else:
            renWin.SetSize(
                int(self.WIN_H_SCALE*self.SCREEN_SIZE[0]),
                int(self.WIN_V_SCALE*self.SCREEN_SIZE[1])
            )

        class MyInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):

            def __init__(self, parent=None):
                return None

        # Initialise interactor
        iren = vtk.vtkRenderWindowInteractor()
        iren.SetInteractorStyle(MyInteractorStyle())
        # iren.AutoAdjustCameraClippingRangeOn()
        iren.SetRenderWindow(renWin)

        return renWin, iren

    def init_video(self):
        """Initialise video recorder"""

        # Set up filter
        imageFilter = vtk.vtkWindowToImageFilter()
        imageFilter.SetInput(self.renWin)
        imageFilter.SetInputBufferTypeToRGB()
        imageFilter.ReadFrontBufferOff()
        imageFilter.Update()

        return imageFilter, 0

    def add_to_ren(self, name, actors, camera, viewport, text):
        """Add elements of scene to renderer window"""

        # Create renderer for scene
        self.ren[name] = vtk.vtkRenderer()

        # Add renderer to render window
        self.renWin.AddRenderer(self.ren[name])

        # Add camera and viewport
        if camera != []:
            self.ren[name].SetActiveCamera(camera)
        self.ren[name].SetViewport(viewport)

        # Add actors
        for key in actors:
            if type(actors[key]) is list:
                for actor in actors[key]:
                    self.ren[name].AddActor(actor)
            else:
                self.ren[name].AddActor(actors[key])

        self.ren[name].ResetCameraClippingRange()

        # Add text
        if type(text) is dict:
            for actor in text:
                self.ren[name].AddActor(text[actor])
        else:
            self.ren[name].AddActor(text)

        self.ren[name].SetBackground(self.COLOUR_BG)

    def create_scenes(self):
        """Create scenes"""

        # Initialise dictionaries
        cameras = {}
        text = {}
        lights = {}

        # Create scenes
        actors, cameras["Main"], text["Main"], lights["Main"] = self.scene_main()

        # Return actors and cameras
        return actors, cameras, text, lights

    def scene_main(self):
        """Create main scene"""

        # Create viewport
        viewport = [0, 0, 1, 1]

        # Camera settings

        # Focal point offset from sat centre
        foffset = [200, -400, 0]

        # Distance from sat
        cam_dist = 5e3

        # Angles
        pitch = -65
        yaw = 2

        # Focal point
        fpoint = np.array([0., 0., -self.SAT_PROPS["Alt"]]) + np.array(foffset)

        # Transform camera position
        prad = pitch*pi/180
        yrad = yaw*pi/180
        Rpitch = np.matrix([
            [cos(prad), 0, sin(prad)],
            [0, 1, 0],
            [-sin(prad), 0, cos(prad)]
        ])
        Ryaw = np.matrix([
            [cos(yrad), -sin(yrad), 0],
            [sin(yrad), cos(yrad), 0],
            [0, 0, 1]
        ])

        cam_pos = Ryaw*Rpitch*np.matrix([-cam_dist, 0., 0.]).T
        cam_pos = np.array(cam_pos).flatten()
        cam_pos = cam_pos + fpoint

        # cam_pos = [-10, 0., -self.SAT_PROPS["Alt"] - cam_dist]

        # Create camera
        camera = vtk.vtkCamera()
        camera.SetPosition(cam_pos)
        camera.SetViewUp(0, 0, -1)
        camera.SetViewAngle(15)
        camera.SetFocalPoint(fpoint)
        camera.SetClippingRange(0.001, 100)

        # Create lights
        lights = []
        lights.append(vtk.vtkLight())
        lights[0].SetPosition(cam_pos)
        lights[0].SetFocalPoint([0., 0., -self.SAT_PROPS["Alt"]])
        lights[0].SetColor(1., 1., 1.)
        lights.append(vtk.vtkLight())
        lights[1].SetPosition(0., 0., 0)
        lights[1].SetFocalPoint([0., 0., -self.SAT_PROPS["Alt"]])

        # Create actors
        actors = {
            "Sat body": self.create_sat_body(),
            "Sat panels": self.create_sat_panels(),
            "Earth": self.create_earth("true", "small"),
            "Forward cam": self.create_cam_fov("Forward"),
            "Redline": self.create_line(self.LSR_POS["Red"], [1., 0., 0.]),
            "Greenline": self.create_line(self.LSR_POS["Green"], [0., 1., 0.]),
            "Blueline": self.create_line(self.LSR_POS["Blue"], [0., 0., 1.])
        }

        for T, pos in zip(range(self.DATA["Target info"]["Num"]), self.DATA["Target info"]["Pos"]):
            actors["T{}".format(T+1)] = self.create_sphere(pos)

        # Text actors
        text = {}

        if self.SHOW_TEXT:
            # Craft text
            text["Craft"] = self.create_text(
                {
                    "String": "CRAFT PROSPECT",
                    "Size": 60,
                    "Font": "Montserrat-SemiBold",
                    "Y offset": 0.06
                },
                viewport
            )

            # Subtitle text
            text["QKD"] = self.create_text(
                {
                    "String": "Demo Simulation",
                    "Size": 40,
                    "Style": "Normal"
                },
                viewport
            )

            # Time text
            text["Time"] = self.create_text(
                {
                    "String": "",
                    "Size": 50,
                    "Anchor": "NE",
                    "Font": "7Segment"
                },
                viewport
            )

            # Info text
            text["Info"] = self.create_text(
                {
                    "String": """Altitude: {:.0f} km
                    Velocity: {:.2f} km/s
                    """.format(
                        self.SAT_PROPS["Alt"]/1000,
                        self.DATA["Vel"][0, 0]/1000,
                    ),
                    "Size": 20,
                    "Anchor": "NE",
                    "Y offset": 0.06
                },
                viewport
            )

        # Render scene
        self.add_to_ren("Main", actors, camera, viewport, text)

        # Reset clipping range
        # camera.SetClippingRange(1000, 1000e3)

        # Return actors to animate
        return actors, camera, text, lights

    def create_sat_body(self):
        """Generate satellite body geometry"""

        # Dimensions of body
        SAT_SIZE = self.ANI_SCALE*self.SAT_SCALE*np.asarray(self.SAT_PROPS["Size"])/2
        bx = SAT_SIZE[0]
        by = SAT_SIZE[1]
        bz = SAT_SIZE[2]

        # Create vertices in body frame
        ind = 0
        V = []
        for x in [-1, 1]:
            for y in [-1, 1]:
                for z in [-1, 1]:
                    V.append((bx*x, by*y, bz*z))

        # Create faces
        F = [
            (0, 1, 3, 2),
            (4, 5, 7, 6),
            (0, 1, 5, 4),
            (2, 3, 7, 6),
            (0, 2, 6, 4),
            (1, 3, 7, 5)
        ]

        # Create building blocks of polydata
        sat = vtk.vtkPolyData()
        points = vtk.vtkPoints()
        polys = vtk.vtkCellArray()
        scalars = vtk.vtkFloatArray()

        # Load the point, cell and data attributes
        for i in range(len(V)):
            points.InsertPoint(i, V[i])
        for i in range(len(F)):
            polys.InsertNextCell(self.mkVtkIdList(F[i]))
        for i in range(len(V)):
            scalars.InsertTuple1(i, i)

        # Assign the pieces to the vtkPolyData.
        sat.SetPoints(points)
        del points
        sat.SetPolys(polys)
        del polys
        sat.GetPointData().SetScalars(scalars)
        del scalars

        # Mapper
        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputData(sat)
        mapper.ScalarVisibilityOff()

        # Actor
        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.GetProperty().SetColor(0.5, 0.5, 0.5)
        actor.GetProperty().SetAmbient(0.5)
        actor.GetProperty().SetSpecular(1.0)
        actor.GetProperty().SetSpecularPower(5.0)
        actor.GetProperty().SetDiffuse(0.2)

        # Move to sat position
        actor.SetPosition(0, 0, -self.SAT_PROPS["Alt"])

        return actor

    def create_sat_panels(self):
        """Create satellite solar panel geometry"""

        # Dimensions of body
        SAT_SIZE = self.ANI_SCALE*self.SAT_SCALE*np.asarray(self.SAT_PROPS["Size"])/2
        bx = SAT_SIZE[0]
        by = SAT_SIZE[1]
        bz = SAT_SIZE[2]

        # Panel length
        L = bx

        # Panels
        theta = self.PANEL_ANGLE*pi/180
        px1 = bx - L*sin(theta)
        py1 = by + L*cos(theta)
        pz1 = bz
        px2 = px1 + L*sin(theta)
        py2 = py1 + L*cos(theta)
        pz2 = pz1

        # Vertices
        V = [
            (-bx, by, -bz),
            (-bx, by, bz),
            (-px1, py1, pz1),
            (-px1, py1, -pz1),
            (-px1, py1, -pz1),
            (-px1, py1, pz1),
            (-px2, py2, pz2),
            (-px2, py2, -pz2),
            (-bx, -by, -bz),
            (-bx, -by, bz),
            (-px1, -py1, pz1),
            (-px1, -py1, -pz1),
            (-px1, -py1, -pz1),
            (-px1, -py1, pz1),
            (-px2, -py2, pz2),
            (-px2, -py2, -pz2)
        ]

        # Create faces
        F = [
            (0, 1, 2, 3),
            (4, 5, 6, 7),
            (8, 9, 10, 11),
            (12, 13, 14, 15)
        ]

        # Create building blocks of polydata
        sat = vtk.vtkPolyData()
        points = vtk.vtkPoints()
        polys = vtk.vtkCellArray()
        scalars = vtk.vtkFloatArray()

        # Load the point, cell and data attributes
        for i in range(len(V)):
            points.InsertPoint(i, V[i])
        for i in range(len(F)):
            polys.InsertNextCell(self.mkVtkIdList(F[i]))
        for i in range(len(V)):
            scalars.InsertTuple1(i, i)

        # Assign the pieces to the vtkPolyData.
        sat.SetPoints(points)
        del points
        sat.SetPolys(polys)
        del polys
        sat.GetPointData().SetScalars(scalars)
        del scalars

        # Mapper
        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputData(sat)
        mapper.ScalarVisibilityOff()

        # Actor
        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.GetProperty().SetColor(0., 0., 0.8)
        actor.GetProperty().SetAmbient(0.5)
        actor.GetProperty().SetSpecular(.5)
        actor.GetProperty().SetSpecularPower(10.0)
        actor.GetProperty().SetDiffuse(0.2)

        # Move to sat position
        actor.SetPosition(0, 0, -self.SAT_PROPS["Alt"])

        return actor

    def create_earth(self, imtype, size):
        """Create tiles for Earth geometry"""

        # Update properties for tile
        tile_props = {
            "Size": self.IMG_PROPS["Texture size"],
            "Translate": (
                -self.IMG_PROPS["Offset"][0],
                -self.IMG_PROPS["Texture size"][1]/2,
                0
            )
        }

        # Texture for tile
        texture = f"{cur_dir}/images/samp1_{size}.jpg"

        # Create actors
        actor = self.create_plane(tile_props, texture)

        return actor

    def create_plane(self, props, texture):
        """Create flat plane"""

        # Pull and scale dimensions
        SIZE = np.asarray(props["Size"])
        POS = np.asarray(props["Translate"])

        # Create texture reader
        reader = vtk.vtkJPEGReader()
        reader.SetFileName(texture)

        # Create texture object
        texture = vtk.vtkTexture()
        texture.SetInputConnection(reader.GetOutputPort())
        texture.InterpolateOn()

        # Create plane model
        plane = vtk.vtkPlaneSource()
        plane.SetResolution(1, 1)
        plane.SetPoint1(0, SIZE[1], 0)
        plane.SetPoint2(SIZE[0], 0, 0)

        # Translate to centre
        transP = vtk.vtkTransform()
        transP.Translate(
            POS[0],
            POS[1],
            POS[2]
        )
        tpd = vtk.vtkTransformPolyDataFilter()
        tpd.SetInputConnection(plane.GetOutputPort())
        tpd.SetTransform(transP)
        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputConnection(tpd.GetOutputPort())
        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.SetTexture(texture)
        actor.GetProperty().SetAmbient(1.0)
        actor.GetProperty().SetSpecular(.5)
        actor.GetProperty().SetSpecularPower(5.0)
        actor.GetProperty().SetDiffuse(0.2)

        return actor

    def create_cam_fov(self, name):
        """Create FOV actor for camera"""

        # Vertices of FOV
        V = [
            (0, 0, -self.SAT_PROPS["Alt"]),
            tuple(self.CAM_PROPS[name]["Intercepts"][:, 0]),
            tuple(self.CAM_PROPS[name]["Intercepts"][:, 1]),
            tuple(self.CAM_PROPS[name]["Intercepts"][:, 2]),
            tuple(self.CAM_PROPS[name]["Intercepts"][:, 3])
        ]

        # Faces of FOV
        F = [(0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 4, 1)]

        # Create building blocks of polydata
        cam = vtk.vtkPolyData()
        points = vtk.vtkPoints()
        polys = vtk.vtkCellArray()
        scalars = vtk.vtkFloatArray()

        # Load the point, cell and data attributes
        for i in range(5):
            points.InsertPoint(i, V[i])
        for i in range(4):
            polys.InsertNextCell( self.mkVtkIdList(F[i]))
        for i in range(5):
            scalars.InsertTuple1(i,i)

        # Assign the pieces to the vtkPolyData.
        cam.SetPoints(points)
        del points
        cam.SetPolys(polys)
        del polys
        cam.GetPointData().SetScalars(scalars)
        del scalars

        # Mapper
        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputData(cam)
        mapper.ScalarVisibilityOff()

        # Actor
        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.GetProperty().SetColor(0.5, 1, 0.5)
        actor.GetProperty().SetAmbient(0.5)
        actor.GetProperty().SetOpacity(0.1)

        return actor

    def create_line(self, pos, colour):
        """Create line"""

        # Absolute source position
        pos_abs = np.array([0., 0., -self.SAT_PROPS["Alt"]]) + np.array(pos)*self.SAT_SCALE

        # Create line
        line = vtk.vtkLineSource()
        line.SetPoint1(pos_abs)
        line.SetPoint2(2*self.SAT_PROPS["Alt"], 0., -self.SAT_PROPS["Alt"])

        # Mapper
        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputConnection(line.GetOutputPort())

        # Actor
        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.GetProperty().SetColor(colour)
        actor.GetProperty().SetOpacity(0.5)
        actor.GetProperty().SetLineWidth(4)
        actor.SetOrigin(0., 0., -self.SAT_PROPS["Alt"])

        return actor

    def create_sphere(self, position):
        """Create sphere of specific size"""

        # Create source
        source = vtk.vtkSphereSource()
        source.SetCenter(0, 0, 0)
        source.SetRadius(1.e3)
        source.SetPhiResolution(40)
        source.SetThetaResolution(40)

        # Mapper
        mapper = vtk.vtkPolyDataMapper()
        if vtk.VTK_MAJOR_VERSION <= 5:
            mapper.SetInput(source.GetOutput())
        else:
            mapper.SetInputConnection(source.GetOutputPort())

        # Actor
        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.GetProperty().SetColor(1, 0.5, 0.5)
        actor.GetProperty().SetAmbient(0.5)
        actor.GetProperty().SetOpacity(0.8)
        actor.SetPosition(position)

        # Return actor
        return actor

    def create_text(self, settings, viewport):
        """Create text actor for view labels"""

        viewport = np.array(viewport)
        viewport[[0, 2]] = self.WIN_H_SCALE*viewport[[0, 2]]
        viewport[[1, 3]] = self.WIN_V_SCALE*viewport[[1, 3]]
        viewport = list(viewport)

        # Set defaults if not specified
        defaults = {
            "Size": 20,
            "Anchor": "SW",
            "X offset": 0.02,
            "Y offset": 0.02,
            "Font": "Montserrat",
            "Colour": self.COLOUR_FONT
        }
        for key in defaults:
            try:
                settings[key]
            except KeyError:
                settings[key] = defaults[key]

        # Position
        margin = (
            self.TEXT_SCALE*settings["X offset"]*(self.ANCHOR[settings["Anchor"]][0] - 1),
            self.TEXT_SCALE*settings["Y offset"]*(self.ANCHOR[settings["Anchor"]][1] - 1)
        )

        posx = int((viewport[0] + 0.5*self.ANCHOR[settings["Anchor"]][0]*(viewport[2] - viewport[0]) - margin[0])*self.SCREEN_SIZE[0])
        posy = int((viewport[1] + 0.5*self.ANCHOR[settings["Anchor"]][1]*(viewport[3] - viewport[1]) - margin[1])*self.SCREEN_SIZE[1])

        # Properties
        props = vtk.vtkTextProperty()
        props.SetFontFamily(vtk.VTK_FONT_FILE)
        if settings["Font"] == "Montserrat-SemiBold":
            props.SetFontFile("./fonts/Montserrat-SemiBold.ttf")
        elif settings["Font"] == "Consolas":
            props.SetFontFile("./fonts/consola.ttf")
        elif settings["Font"] is "7Segment":
            props.SetFontFile("./fonts/digital-7 (mono).ttf")
        else:
            props.SetFontFile("./fonts/Montserrat.ttf")

        props.SetFontSize(int(self.TEXT_SCALE*settings["Size"]))
        props.SetColor(settings["Colour"])
        props.SetJustification(self.ANCHOR[settings["Anchor"]][0])
        props.SetVerticalJustification(self.ANCHOR[settings["Anchor"]][1])

        # Create actor
        actor = vtk.vtkTextActor()
        actor.SetInput(settings["String"])
        actor.SetDisplayPosition(posx, posy)
        actor.SetTextProperty(props)

        return actor

    def execute(self, obj, event):
        """Execute timed event"""

        # Reset clipping range
        # self.cameras["Main"].SetClippingRange(1000, 3000e3)

        # Simulation time
        T = self.DATA["Time"][self.index]

        # Visualisation time
        Tvis = T*self.TIME_SCALE

        # Modes
        adcs_mode = self.DATA["ADCS mode names"][int(self.DATA["ADCS mode"][self.index])]
        payload_mode = self.DATA["Payload mode names"][int(self.DATA["Payload mode"][self.index])]

        # Update Earth position
        self.actors["Earth"].SetPosition(
            -self.DATA["Pos"][0, self.index],
            0,
            0
        )

        # Update target positions
        for trgt, pos in zip(range(self.DATA["Target info"]["Num"]), self.DATA["Target info"]["Pos"]):
            self.actors["T{}".format(trgt+1)].SetPosition(
                -self.DATA["Pos"][0, self.index] + pos[0],
                pos[1],
                pos[2]
            )

        # Update sightline
        att_des = tuple(np.array(self.DATA["Inputs"][:, self.index])*180/pi)
        self.actors["Redline"].SetOrientation(att_des)
        self.actors["Greenline"].SetOrientation(att_des)
        self.actors["Blueline"].SetOrientation(att_des)

        if payload_mode in ["Synchronise"]:
            self.actors["Redline"].GetProperty().SetOpacity(0)
            self.actors["Greenline"].GetProperty().SetOpacity(0.9)
            self.actors["Blueline"].GetProperty().SetOpacity(0)
        elif payload_mode in ["Authenticate"]:
            self.actors["Redline"].GetProperty().SetOpacity(0)
            self.actors["Greenline"].GetProperty().SetOpacity(0)
            self.actors["Blueline"].GetProperty().SetOpacity(0.9)
        elif payload_mode in ["Key delivery"]:
            self.actors["Redline"].GetProperty().SetOpacity(0.9)
            self.actors["Greenline"].GetProperty().SetOpacity(0)
            self.actors["Blueline"].GetProperty().SetOpacity(0.9)
        else:
            self.actors["Redline"].GetProperty().SetOpacity(0)
            self.actors["Greenline"].GetProperty().SetOpacity(0)
            self.actors["Blueline"].GetProperty().SetOpacity(0)

        # Update satellite attitude
        att = tuple(np.array(self.DATA["Att"][:, self.index])*180/pi)
        for key in ["Sat body", "Sat panels"]:
            self.actors[key].SetOrientation(att)

        # Update text actors
        hh = self.init_time[0]
        ss = int(self.init_time[2] + Tvis)
        mm = self.init_time[1] + (ss // 60)
        ss =  ss % 60
        hh = hh + (mm // 60)
        mm = mm % 60
        self.text["Main"]["Time"].SetInput(
            "{:02d}:{:02d}:{:02d}".format(hh, mm, ss)
        )
        # Update render window interactor
        self.iren = obj
        self.iren.GetRenderWindow().Render()

        # Increment index, loop if at end of data
        if self.index < len(self.DATA["Time"]) - 1:
            self.index += 1
        else:
            self.index = 0

    def mkVtkIdList(self, it):
        """Makes a vtkIdList from a Python iterable"""
        vil = vtk.vtkIdList()
        for i in it:
            vil.InsertNextId(int(i))
        return vil


import math
import numpy as np
from scipy.spatial import ConvexHull

class LOS_guidance():
    def __init__(self, params):
        self.ship_max_speed = params['ship_max_speed']
        self.ship_ax_vel_lim = params['ship_ax_vel_lim']
        self.ship_lat_acc_pos_lim = params['ship_lat_acc_pos_lim']
        self.ship_lat_acc_neg_lim = params['ship_lat_acc_neg_lim']
        self.ship_ax_acc_lim = params['ship_ax_acc_lim']
        self.T_max_thrust = params['T_max_thrust']
        self.T_min_thrust = params['T_min_thrust']

    def ship_los_guidance(self, ship_phys_status, target_pos, dt=1 / 60):

        ship_position = ship_phys_status['pose'][0]
        heading_in = ship_phys_status['pose'][1]
        ship_speed_in = np.linalg.norm(ship_phys_status['velocity'][0])
        ship_rot_spd_in = ship_phys_status['velocity'][1]

        def angle_between_vector_and_angle(vector, angle):
            # Calculate the angle between the vector and the x-axis
            vector_angle = math.atan2(vector[1], vector[0])

            # Calculate the difference between the vector angle and the given angle
            angle_diff = vector_angle - angle

            # Ensure that the angle difference is within the range (-pi, pi]
            while angle_diff > math.pi:
                angle_diff -= 2 * math.pi
            while angle_diff <= -math.pi:
                angle_diff += 2 * math.pi

            # Return the absolute value of the angle difference
            return angle_diff

        ship_heading = heading_in
        ship_rot_spd = ship_rot_spd_in
        ship_speed = 0

        distance_to_target = math.sqrt(
            (target_pos[0] - ship_position[0]) ** 2 + (target_pos[1] - ship_position[1]) ** 2)

        if not (distance_to_target >= -1 and distance_to_target <= 10000):
            angle_variance = 0

        target_angle = (target_pos - ship_position)

        angle_variance = angle_between_vector_and_angle(target_angle, ship_heading)

        rotational_mul = angle_variance

        if not (angle_variance >= -10 and angle_variance <= 10):
            angle_variance = 0

        if (angle_variance) > (math.pi / 4):
            rotational_mul = abs((math.pi / 2))
        elif (angle_variance) < -(math.pi / 2):
            rotational_mul = - abs((math.pi / 2))

        # rotational controller
        if abs(angle_variance) > 0.01 and abs(ship_rot_spd) <= abs(self.ship_ax_vel_lim):
            ship_rot_spd = -(rotational_mul / (math.pi / 2))*10
        else:
            ship_rot_spd = 0

            # translational controller
        if distance_to_target > 2:
            ship_speed = self.ship_max_speed
        elif distance_to_target >= 0.6:
            ship_speed = self.ship_max_speed/3
        elif distance_to_target >= 0.3:
            ship_speed = self.ship_max_speed/8
        else:
            ship_speed = 0
            ship_rot_spd = 0

        ship_vel = ship_speed*np.array([math.cos(heading_in), math.sin(heading_in)])

        cmd_vel = [ship_vel, ship_rot_spd]

        #print("\rangle_variance, ship_rot_spd", np.degrees(heading_in), ship_rot_spd, end="")
        #print("\rTLeft, TRight", rTLeft.TRight, end="")

        return cmd_vel

class LOS_VO_guidance():

    def __init__(self, params):

        self.ship_max_speed = params['ship_max_speed']
        self.ship_ax_vel_lim = params['ship_ax_vel_lim']
        self.ship_lat_acc_pos_lim = params['ship_lat_acc_pos_lim']
        self.ship_lat_acc_neg_lim = params['ship_lat_acc_neg_lim']
        self.ship_ax_acc_lim = params['ship_ax_acc_lim']
        self.T_max_thrust = params['T_max_thrust']
        self.T_min_thrust = params['T_min_thrust']
        self.detection_range = 10
        self.spd_visual_multiplier = 2.5

        self.los = LOS_guidance(params)
        self.vo_polygons = []

        #parameters

    def ship_los_vo_guidance(self, phys_status, output_polygon, target_pos, sensor_data, dt=1 / 60):
        #   First, this receives a database of ships in the world. the database is a dictionary
        #   if there are no obstacles in range, it pursues the target using Line-of-sight guidance law
        #   if there are VO cones in sight, it tries to evade the obstacle by maintaining speed and turning.
        #   it prefers angles closer to the target.
        #   if no trajectory is valid, it tries to decelerate to half the maximum speed
        #   if there is still no trajectory, it tries to stop.

        #setting up variables
        self.phys_status = phys_status  # updates phys status
        self.output_polygon = output_polygon
        self.sensor_data = sensor_data  # get sensor_data
        self.vo_lines = []
        self.vo_circles = []  # position and radius
        self.vo_cones = []
        self.vo_polygons = []
        ship_position = phys_status['pose'][0]
        heading_in = phys_status['pose'][1]
        ship_speed_in = np.linalg.norm(phys_status['velocity'][0])
        ship_rot_spd_in = phys_status['velocity'][1]
        ship_heading = heading_in
        ship_rot_spd = ship_rot_spd_in
        ship_speed = 0

        # recieving and processing the data
        self.filtered_objects_angle = self.sensor_simulator()  # process the data
        self.vo_cone_generator() #generates VO cone

        # target_information
        distance_to_target = math.sqrt((target_pos[0] - ship_position[0]) ** 2 + (target_pos[1] - ship_position[1]) ** 2)
        target_vector = (target_pos - ship_position)
        target_angle = self.regularize_angle(math.atan2(target_vector[1], target_vector[0]))

        # search for valid angle
        target_speed = 2.0
        self.angle_opacity = self.vo_theta_opacity(target_angle, target_speed)
        angle_rad = math.radians(3*self.index_with_lowest_number(self.angle_opacity))
        angle_variance = self.regularize_angle(angle_rad - ship_heading)
        if abs(angle_variance) > math.pi * (1 / 8):
            target_speed = 1.5
            self.angle_opacity = self.vo_theta_opacity(target_angle, target_speed)
            angle_rad = math.radians(3 * self.index_with_lowest_number(self.angle_opacity))
            angle_variance = self.regularize_angle(angle_rad - ship_heading)

            if abs(angle_variance) > math.pi * (1.5 / 8):
                target_speed = 1.0
                self.angle_opacity = self.vo_theta_opacity(target_angle, target_speed)
                angle_rad = math.radians(3 * self.index_with_lowest_number(self.angle_opacity))
                angle_variance = self.regularize_angle(angle_rad - ship_heading)

                if abs(angle_variance) > math.pi * (1 / 4):
                    target_speed = 0.5
                    self.angle_opacity = self.vo_theta_opacity(target_angle, target_speed)
                    angle_rad = math.radians(3 * self.index_with_lowest_number(self.angle_opacity))
                    angle_variance = self.regularize_angle(angle_rad - ship_heading)

                    if abs(angle_variance) > math.pi * (5 / 8):
                        target_speed = -0.5
                        self.angle_opacity = self.vo_theta_opacity(target_angle, target_speed)
                        angle_rad = math.radians(3 * self.index_with_lowest_number(self.angle_opacity))
                        angle_variance = self.regularize_angle(angle_rad - ship_heading)

        for theta in range(0,120):
            point = np.array(
                [self.spd_visual_multiplier*target_speed * math.cos(math.radians(theta*3)), self.spd_visual_multiplier*target_speed * math.sin(math.radians(theta*3))])

            if self.angle_opacity[theta] < 1:  #np.percentile(self.angle_opacity,10):
                self.vo_circles.append([self.phys_status["pose"][0]+point,0.05, (0,255,50), 1])

        self.vo_lines.append([self.phys_status["pose"][0],[self.phys_status["pose"][0][0]+self.spd_visual_multiplier*target_speed*math.cos(angle_rad),self.phys_status["pose"][0][1]+self.spd_visual_multiplier*target_speed*math.sin(angle_rad)],(0,255,0)])

        rotational_mul = angle_variance

        if target_speed < 0:
            rotational_mul = - rotational_mul

        if not (angle_variance >= -10 and angle_variance <= 10):
            angle_variance = 0

        if (angle_variance) > (math.pi / 2):
            rotational_mul = abs((math.pi / 2))
        elif (angle_variance) < -(math.pi / 2):
            rotational_mul = - abs((math.pi / 2))

        # rotational controller
        if abs(angle_variance) > 0.01 and abs(ship_rot_spd) <= abs(self.ship_ax_vel_lim):
            ship_rot_spd = -(rotational_mul / (math.pi / 2))*10
        else:
            ship_rot_spd = 0

        # translational controller
        if distance_to_target > 2:
            ship_speed = target_speed
        elif distance_to_target >= 0.6:
            ship_speed = target_speed/3
        elif distance_to_target >= 0.3:
            ship_speed = target_speed/8
        else:
            ship_speed = 0
            ship_rot_spd = 0

        ship_vel = ship_speed*np.array([math.cos(heading_in), math.sin(heading_in)])
        cmd_vel = [ship_vel, ship_rot_spd]

        return cmd_vel

    def vo_cone_generator(self):
        ship_pos = self.phys_status["pose"][0]
        ship_vel = self.phys_status["velocity"][0]
        ship_spd = abs(np.linalg.norm(self.phys_status["velocity"][0]))

        #vessel velocity indicator
        self.vo_lines.append([ship_pos,ship_pos+ship_vel*self.spd_visual_multiplier, (0, 0, 255)])

        circle_color = (200, 200, 200, 255)
        line_width = 1
        circle = [ship_pos, self.detection_range, circle_color, line_width]  # object circle position
        self.vo_circles.append(circle)  # circle representing collision distance of the object

        if self.filtered_objects_angle != None:
            for key, object in self.filtered_objects_angle.items():

                object_pos = object[0].phys_status["pose"][0]  # absolute object position
                object_vel = object[0].phys_status["velocity"][0]  # absolute object velocity
                #object_radius = object[1] + object[2]  # object VO_circle radius
                circle_color = (200, 0, 0, 255)
                line_width = 1
                #circle = [object_pos, object_radius, circle_color, line_width]  # object circle position
                #self.vo_circles.append(circle)  # circle representing collision distance of the object
                pos_diff = object_pos - ship_pos

                object_distance = object[3]  # distance from the object to the circle

                rel_spd = np.linalg.norm(object[0].phys_status["velocity"][0]-ship_vel)

                if object_distance < 0.1:  # for avoiding divide by zero error
                    object_distance = 0.1

                start_rad = object[1]
                end_rad = object[2]

                object_velocity = object[0].phys_status["velocity"][0]

                #self.vo_cones.append([ship_pos, [start_rad, end_rad], object_distance*math.cos(tangent_angle)])

                self.vo_cones.append([ship_pos+object_velocity*self.spd_visual_multiplier, [start_rad, end_rad], object_distance])

            #print(math.degrees(self.filtered_objects))
        pass

    def vo_theta_opacity(self, target_angle, spd_to_search):

        # when search spd = max_spd
        spd_to_search
        angle_opacity = np.linspace(start=0, stop=120, num=120, endpoint=False)

        for theta in range(0,120):

            delta_angle = target_angle - math.radians(theta*3)

            while delta_angle >= 1 * math.pi:
                delta_angle = delta_angle - 2 * math.pi
            while delta_angle <= -1 * math.pi:
                delta_angle = delta_angle + 2 * math.pi

            angle_diff_opacity = (abs(delta_angle/(math.pi)))*(30/80)

            angle_opacity[theta] = angle_diff_opacity

        for vo_cone in self.vo_cones:
            for theta in range(0, 120):
                point = np.array([self.spd_visual_multiplier*spd_to_search*math.cos(math.radians(theta*3)), self.spd_visual_multiplier**spd_to_search*math.sin(math.radians(theta*3))])

                opacity = self.vo_cone_collision_detector(point + self.phys_status["pose"][0], vo_cone)

                if opacity > 1/5:
                    opacity = 100

                if opacity <1/10:
                    opacity = 0

                angle_opacity[theta] = angle_opacity[theta]+(opacity**2)*10

        return angle_opacity

    def sensor_simulator_legacy(self):
        # receives dict(self.ships_database, **self.obstacle_database), which consists of dictionaries of objects(ship or obstacle).
        # extracts only {key, polygon} tuples using a for loop
        # then it filters only the keys of which its polygon is inside the detection range.
        # then it outputs {key: [polygon, phys_status]}  to a dictionary.
        ship_pose = self.phys_status["pose"]
        ship_polygon = self.output_polygon
        objects_database = self.sensor_data
        origin_point = ship_pose[0]

        if not(objects_database):
            return

        filtered_objects = {}

        #print(objects_database)

        for key, object in objects_database.items():
            # calculate distance between origin and closest point of polygon

            # print(key)
            object_pose = object.phys_status["pose"]
            object_vector = (object_pose[0] - ship_pose[0])
            object_distance = (np.linalg.norm(object_vector))
            #print(key, object_vector)

            # check if polygon is within detection range
            if object_distance <= self.detection_range:
                # gets object polygonal information
                poly_points = object.output_polygon
                # if there are no polygons, return nothing
                if poly_points == None:
                    return

                #print(poly_points)
                (max_angle, min_angle) = self.get_min_max_angles(poly_points)
                FOV = (max_angle - min_angle)

                while FOV > 1 * math.pi:
                    FOV = 2 * math.pi - FOV
                while FOV <= 0:
                    FOV += 2 * math.pi

                object_radius = (object_distance * math.tan(FOV / 2))
                self_radius = (self.get_largest_inner_product(ship_polygon, object_vector))/2

                filtered_objects[key] = [object, object_radius, self_radius ]
                #print(" key, FOV object_radius self_radius  : ", object_distance, math.degrees(FOV), object_radius, self_radius)
        return filtered_objects

    def sensor_simulator(self):
        # receives dict(self.ships_database, **self.obstacle_database), which consists of dictionaries of objects(ship or obstacle).
        # extracts only {key, polygon} tuples using a for loop
        # then it filters only the keys of which its polygon is inside the detection range.
        # then it outputs {key: [polygon, phys_status]}  to a dictionary.
        ship_pose = self.phys_status["pose"]
        ship_polygon = self.output_polygon
        objects_database = self.sensor_data
        origin_point = ship_pose[0]

        if not (objects_database):
            return

        filtered_objects_angle = {}

        # print(objects_database)

        for key, object in objects_database.items():
            # calculate distance between origin and closest point of polygon

            # print(key)
            object_pose = object.phys_status["pose"]
            object_vector = (object_pose[0] - ship_pose[0])

            if object_pose[0][1] == ship_pose[0][1] and object_pose[0][0] == ship_pose[0][0]:
                continue
            object_distance = (np.linalg.norm(object_vector))
            # print(key, object_vector)

            # check if polygon is within detection range
            if object_distance > self.detection_range*1.1:
                continue

                # print(poly_points)
            N = self.inflate_obstacles(object)
            if N == None:
                continue
            [max_angle_point, min_angle_point], [start_angle, end_angle], self.outer_polygon,closest_distance = N

            self.vo_lines.append([self.phys_status["pose"][0], max_angle_point,(255, 153, 251)])
            self.vo_lines.append([self.phys_status["pose"][0], min_angle_point,(255, 153, 251)])
            if closest_distance <= self.detection_range:

                filtered_objects_angle[key] = [object, start_angle, end_angle, closest_distance]
                # print(" key, FOV object_radius self_radius  : ", object_distance, math.degrees(FOV), object_radius, self_radius)
        return filtered_objects_angle

    def get_min_max_angles(self,polygon):
        # Select the first point as the origin
        origin = self.phys_status["pose"][0]

        # Calculate the angle for each point relative to the origin
        angles = []
        for point in polygon:
            x, y = point[0] - origin[0], point[1] - origin[1]
            angle = math.atan2(y, x)
            if angle < 0:
                while angle < 0:
                    angle += 2 * math.pi

            if angle > 2 * math.pi:
                while angle > 2:
                    angle -= 2 * math.pi
            angles.append(angle)

        # Return the maximum and minimum angles
        max_angle = max(angles)
        min_angle = min(angles)

        #print("\n",math.degrees(max_angle), math.degrees(min_angle),end="")
        #print("\n", polygon, end="")

        return (max_angle, min_angle)

    def inflate_obstacles(self,object):
        # Select the first point as the origin
        origin = self.phys_status["pose"][0]
        ship_polygon = self.output_polygon
        if object.output_polygon == None:
            return

        # Calculate the angle for each point relative to the origin
        object_vector = (object.phys_status["pose"][0] - self.phys_status["pose"][0])
        avg_angle = math.atan2(object_vector[1],object_vector[0])
        if avg_angle < 0:
            while avg_angle < 0:
                avg_angle += 2 * math.pi
        if avg_angle > 2 * math.pi:
            while avg_angle > 2:
                avg_angle -= 2 * math.pi
        #centers the ship polygon
        ship_polygon_centered = []
        for point in self.output_polygon:
            ship_polygon_centered.append((point - self.phys_status["pose"][0])*2)

        inflated_points = []
        for point in object.output_polygon:
            for point2 in ship_polygon_centered:
                inflated_point = point + point2
                inflated_points.append(inflated_point)

        hull = ConvexHull(inflated_points)
        outer_polygon = [inflated_points[i] for i in hull.vertices]

        self.vo_polygons.append(outer_polygon)

        angles = []
        for point in outer_polygon:
            x, y = point[0] - origin[0], point[1] - origin[1]
            angle = math.atan2(y, x)

            if angle < 0:
                while angle < 0:
                    angle += 2 * math.pi

            if angle > 2 * math.pi:
                while angle > 2 * math.pi:
                    angle -= 2 * math.pi

            delta_angle = angle-avg_angle

            if delta_angle < - math.pi:
                while delta_angle < -math.pi:
                    delta_angle += 2 * math.pi

            if delta_angle > math.pi:
                while delta_angle > math.pi:
                    delta_angle -= 2 * math.pi

            angles.append(delta_angle)

        # Return the maximum and minimum angles
        max_angle = max(angles)
        min_angle = min(angles)

        max_angle_index = angles.index(max_angle)
        min_angle_index = angles.index(min_angle)

        max_angle = min(max(angles), math.pi*(3/4))+math.pi/20
        min_angle = max(min(angles), -math.pi*(3/4))-math.pi/20

        max_angle_point = outer_polygon[max_angle_index]
        min_angle_point = outer_polygon[min_angle_index]

        closest_point = self.closest_point_to_polygon(origin, outer_polygon)

        self.vo_circles.append([closest_point[0], 0.1, (236, 232, 26), 1])

        if closest_point[1] == -1:
            closest_distance = 1
        else:
            closest_distance = np.linalg.norm(origin - closest_point[0])

        return ([max_angle_point,min_angle_point],[avg_angle+min_angle,avg_angle+max_angle],outer_polygon,closest_distance)

    def get_largest_inner_product(self,polygon, B):
        # Rotate B by pi/2
        B_rotated = np.array([-B[1], B[0]])

        # Normalize B_rotated
        A = B_rotated / np.linalg.norm(B_rotated)

        max_inner_product = -float('inf')

        for i, point1 in enumerate(polygon):
            for j, point2 in enumerate(polygon[i + 1:], i + 1):
                # Calculate the line vector between point1 and point2
                line_vector = np.array(point2) - np.array(point1)

                # Calculate the inner product of line_vector and A
                inner_product = np.dot(line_vector / np.linalg.norm(line_vector), A)

                # Update the max inner product if applicable
                if inner_product > max_inner_product:
                    max_inner_product = inner_product

        # Return the largest inner product
        return max_inner_product

    def tangent_lines(self, circle, origin):
        # Unpack circle coordinates and radius
        x_c, y_c = circle[0]
        r = circle[1]

        # Unpack origin coordinates
        x_o, y_o = origin

        # Calculate the distance between the origin and the center of the circle
        d = math.sqrt((x_c - x_o) ** 2 + (y_c - y_o) ** 2)

        # Check if the origin is inside the circle
        if d < r:
            print("Error: origin is inside the circle.")
            return None

        # Calculate the angle between the origin and the center of the circle
        theta = math.atan2(y_c - y_o, x_c - x_o)

        # Calculate the distance from the origin to the tangent point
        a = math.sqrt(d ** 2 - r ** 2)

        # Calculate the angles of the tangent lines
        alpha = math.asin(r / d)
        beta = theta - alpha
        gamma = theta + alpha

        # Return the two angles of the tangent lines
        return beta, gamma

    def vo_cone_collision_detector(self, point, cone):
        """
        Determines whether a point is inside a circle section
        """
        origin, [start_angle, end_angle], radius = cone

        if radius < 0.5:
            radius = 1

        # Calculate angle of point relative to circle origin
        point_angle = math.atan2(point[1] - origin[1], point[0] - origin[0])

        start_angle = self.regularize_angle(start_angle)
        end_angle = self.regularize_angle(end_angle)
        point_angle = self.regularize_angle(point_angle)

        if end_angle >= start_angle:
            result = point_angle >= start_angle and point_angle <= end_angle
            inside_angle = end_angle - start_angle

        elif end_angle <= start_angle: # 0도 넘어갈 때
            result = point_angle >= start_angle or point_angle <= end_angle
            inside_angle = end_angle + 2*math.pi - start_angle

        if result == True:
            time_till_collision = radius / (math.dist(point, origin)/5)

            print(1)

            if radius < 4:
                return 1

            if inside_angle > math.pi:
                return 1

            return 1/time_till_collision
        if result == False:
            return 0

    def angle_between_vector_and_angle(self, vector, angle):
        # Calculate the angle between the vector and the x-axis
        vector_angle = math.atan2(vector[1], vector[0])

        # Calculate the difference between the vector angle and the given angle
        angle_diff = vector_angle - angle

        # Ensure that the angle difference is within the range (-pi, pi]

        angle_diff = self.regularize_angle(angle_diff)

        # Return the absolute value of the angle difference
        return angle_diff

    def index_with_lowest_number(self, numbers):
        """
        Returns the index of the lowest number in a list
        """
        lowest_index = 0
        for i in range(1, len(numbers)):
            if numbers[i] < numbers[lowest_index]:
                lowest_index = i
        return lowest_index

    def regularize_angle(self,angle):
        while angle > math.pi:
            angle -= 2 * math.pi
        while angle <= -math.pi:
            angle += 2 * math.pi

        return angle

    def point_polygon_distance(self, point, polygon):
        if isinstance(point, np.ndarray):
            point = tuple(point)

        polygon_vertices = polygon
        # Create a list of tuples containing the x,y coordinates of the polygon vertices
        polygon = [(x, y) for (x, y) in polygon_vertices]

        # Find the closest point on the polygon boundary to the target point
        closest_point = None
        min_distance = float('inf')
        for i in range(len(polygon)):
            x1, y1 = polygon[i]
            x2, y2 = polygon[(i + 1) % len(polygon)]
            dx = x2 - x1
            dy = y2 - y1
            dot = ((point[0] - x1) * dx + (point[1] - y1) * dy) / (dx ** 2 + dy ** 2)
            closest_x = float(x1) + dot * dx
            closest_y = float(y1) + dot * dy
            distance = math.sqrt((point[0] - closest_x) ** 2 + (point[1] - closest_y) ** 2)
            if distance < min_distance:
                min_distance = distance
                closest_point = (closest_x, closest_y)

                print(distance)

        # If the point is inside the polygon, return a negative distance
        if self.is_inside_polygon(point, polygon_vertices):
            return 0
        else:
            return min_distance

    def closest_point_to_polygon(self, point, polygon_vertices):
        # Convert numpy array to tuple if necessary
        if isinstance(point, np.ndarray):
            point = tuple(point)

        # Find the closest point on the polygon boundary to the target point
        closest_point = None
        min_distance = float('inf')

        polygon_vertices2 = self.subdivide_polygon(polygon_vertices)

        for i in range(len(polygon_vertices2)):

            (closest_x, closest_y) = polygon_vertices2[i]

            distance = np.sqrt((point[0] - closest_x) ** 2 + (point[1] - closest_y) ** 2)
            if distance < min_distance:
                min_distance = distance

                closest_point = np.array([closest_x, closest_y])

        if self.is_inside_polygon(point, polygon_vertices):
            return [closest_point, -1]
        else:
            return [closest_point, 1]

    def is_inside_polygon(self, point, polygon_vertices):
        # Create a list of tuples containing the x,y coordinates of the polygon vertices
        polygon = [(x, y) for x, y in polygon_vertices]

        # Use the winding number algorithm to check if the point is inside the polygon
        wn = 0
        for i in range(len(polygon)):
            x1, y1 = polygon[i]
            x2, y2 = polygon[(i + 1) % len(polygon)]
            if y1 <= point[1]:
                if y2 > point[1]:
                    if (point[0] - x1) * (y2 - y1) > (x2 - x1) * (point[1] - y1):
                        wn += 1
            else:
                if y2 <= point[1]:
                    if (point[0] - x1) * (y2 - y1) < (x2 - x1) * (point[1] - y1):
                        wn -= 1
        return wn != 0

    def subdivide_polygon(self, polygon, n=20):
        """Subdivides a polygon and divides each edge into n segments."""
        new_polygon = []

        # Iterate over the edges of the polygon
        for i in range(len(polygon)):
            # Add the current vertex to the new polygon
            new_polygon.append(polygon[i])

            # Calculate the difference vector between the current and next vertex
            diff = [polygon[(i + 1) % len(polygon)][j] - polygon[i][j] for j in range(len(polygon[0]))]

            # Calculate the size of each segment along the current edge
            segment_size = [diff[j] / n for j in range(len(diff))]

            # Iterate over the segments of the current edge
            for j in range(1, n):
                # Calculate the coordinates of the new vertex
                x_new = polygon[i][0] + j * segment_size[0]
                y_new = polygon[i][1] + j * segment_size[1]
                new_vertex = [x_new, y_new]

                # Add the new vertex to the new polygon
                new_polygon.append(new_vertex)

        return new_polygon


#!/usr/bin/env python
# coding: utf-8

# In[1]:

import requests
import bs4

# In[2]:

'http://books.toscrape.com/catalogue/page-2.html'

# In[3]:

'http://books.toscrape.com/catalogue/page-3.html'

# In[4]:

base_url = 'http://books.toscrape.com/catalogue/page-{}.html'

# In[5]:

base_url.format('20')

# In[9]:

page_num = 18

# In[7]:

'http://books.toscrape.com/catalogue/page-{page_num}.html'

# In[10]:

base_url.format(page_num)

# In[12]:

res = requests.get(base_url.format(1))

# In[13]:

soup = bs4.BeautifulSoup(res.text,'lxml')

# In[14]:

soup

# In[15]:

soup.select(".product_pod")

# In[17]:

len(soup.select(".product_pod"))

# In[18]:

products = soup.select(".product_pod")

# In[19]:

example = products[0]

# In[20]:

example

# In[21]:

'star-rating Thr' in str(example)

# In[22]:

example.select(".star-rating.Two")

# In[23]:

example.select('a')

# In[24]:

example.select('a')[1]

# In[25]:

example.select('a')[1]['title']

# In[28]:

two_star_titles = []
for n in range(1,51):
   scrape_url = base_url.format(n)
   res = requests.get(scrape_url)

   soup = bs4.BeautifulSoup(res.text, 'lxml')
   books = soup.select(".product_pod")

   for book in books:
    if len(book.select('.star-rating.Two')) != 0:
        book_title = book.select('a')[1]['title']
        two_star_titles.append(book_title)

# In[29]:

two_star_titles

# In[ ]:


import bs4
import requests
from bs4 import BeautifulSoup

SUPPORTED_LANGUAGES = ("EN", "__test__")

def scrape_oxford_learners_dictionary(word: str) -> list[str]:
    def url(i: int) -> str:
        return (
            f"https://www.oxfordlearnersdictionaries.com"
            f"/definition/english/{word}_{i}"
        )

    # The website filters out requests without a proper User-Agent
    headers = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) "
                      "Gecko/20100101 Firefox/42.0",
    }

    list_of_definitions = []

    for i in range(1, 5, 1):
        response = requests.get(url(i), headers=headers)
        if response.status_code != 200:
            break
        page = response.text
        soup = BeautifulSoup(page, "html.parser")

        find_pos = soup.find("span", class_="pos")
        if isinstance(find_pos, bs4.Tag):
            pos = find_pos.text
        else:
            pos = "-"

        find_senses = soup.find("ol", class_="senses_multiple")
        if isinstance(find_senses, bs4.Tag):
            list_of_senses = find_senses.find_all(
                "li", class_="sense", recursive=False
            )

        else:
            find_senses = soup.find("ol", class_="sense_single")
            if isinstance(find_senses, bs4.Tag):
                list_of_senses = find_senses.find_all(
                    "li", class_="sense", recursive=False
                )
            else:
                break

        for sense in list_of_senses:
            definition = sense.find("span", class_="def")
            list_of_definitions.append(f"({pos}) " + definition.text)

    return list_of_definitions


# pylint: disable=redefined-outer-name
# pylint: disable=unused-argument
# pylint: disable=unused-variable
import os
import shutil
from pathlib import Path
from typing import Callable

import pytest
import yaml

@pytest.fixture
def tmp_compose_spec(tests_data_dir: Path, tmp_path: Path):
    src = tests_data_dir / "docker-compose-meta.yml"
    dst = tmp_path / "docker-compose-meta.yml"
    shutil.copyfile(src, dst)
    return dst

def test_create_new_osparc_config(
    run_program_with_args: Callable, tmp_compose_spec: Path
):
    osparc_dir = tmp_compose_spec.parent / ".osparc"
    assert not osparc_dir.exists()

    result = run_program_with_args(
        "config",
        "--from-spec-file",
        str(tmp_compose_spec),
    )
    assert result.exit_code == os.EX_OK, result.output

    assert osparc_dir.exists()

    meta_cfgs = set(osparc_dir.glob("./*/metadata.y*ml"))
    runtime_cfgs = set(osparc_dir.glob("./*/runtime.y*ml"))

    assert len(runtime_cfgs) == len(meta_cfgs)
    assert {f.parent for f in meta_cfgs} == {f.parent for f in runtime_cfgs}

    service_names = set(yaml.safe_load(tmp_compose_spec.read_text())["services"].keys())
    assert service_names == set({f.parent.name for f in meta_cfgs})


from sklearn import model_selection
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split

import pandas

#names=['Total no of questions','Average time to solve each questions','No of questions marked for review','No of questions right','Average no of clicks in each page']
dataset = pandas.read_csv("dataset.csv")
#dataset = dataset.apply(pandas.to_numeric,errors='ignore')
##cols.remove('Index')
##cols = dataset.columns
##for col in cols:
##    try:
##        dataset[col] = float(dataset[col])
##    except:
##        pass
array = dataset.values
array=array[1:]
X = array[:,0:5]
Y = array[:,5]
print(X)
print(Y)
validation_size = 0.20
seed = 7
X_train, X_validation, Y_train, Y_validation = model_selection.train_test_split(X, Y, test_size=validation_size, random_state=seed)
print("X_train",X_train)
print("Y_train",Y_train)
print("X_validation",X_validation)
print("Y_validation",Y_validation)
seed = 7
scoring = 'accuracy'
# Spot Check Algorithms
models = []
models.append(('LR', LogisticRegression()))
models.append(('LDA', LinearDiscriminantAnalysis()))
models.append(('KNN', KNeighborsClassifier()))
models.append(('CART', DecisionTreeClassifier()))
models.append(('NB', GaussianNB()))
models.append(('SVM', SVC()))
# evaluate each model in turn
results = []
names = []
for name, model in models:
	kfold = model_selection.KFold(n_splits=10, random_state=seed)
	cv_results = model_selection.cross_val_score(model, X_train, Y_train, cv=kfold, scoring=scoring)
	results.append(cv_results)
	names.append(name)
	msg = "%s: %f (%f)" % (name, cv_results.mean(), cv_results.std())
	print(msg)
knn = KNeighborsClassifier()
knn.fit(X_train, Y_train)
predictions = knn.predict(X_validation)
print("Actual Validators",Y_validation)
print("predictions",predictions)
print(accuracy_score(Y_validation, predictions))
print(confusion_matrix(Y_validation, predictions))
print(classification_report(Y_validation, predictions))

model = DecisionTreeClassifier()
model.fit(X_train, Y_train)
# make predictions
predictions = model.predict(X_validation)
#prediction = model.predict([[2.8,15,18,180]])
#print("prediction",prediction)
# summarize the fit of the model
print("predictions",predictions)
print(accuracy_score(Y_validation, predictions))
print(confusion_matrix(Y_validation, predictions))
print(classification_report(Y_validation, predictions))


from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from entrepreneur.models import Usuario
from authentication.serializers import UserListSerializers, UserSerializer

@api_view(['GET', 'POST'])
def user_api_view(request):
    # lista los usuarios activos ingresados al sistemna
    if request.method == 'GET':
        users = Usuario.objects.filter(is_active=True).values('id', 'username', 'email', 'password', 'first_name')
        user_serializer = UserListSerializers(users, many=True)
        return Response(user_serializer.data, status=status.HTTP_200_OK)
    elif request.method == 'POST':
        """
            Habilita la creación de usuarios solicitando
        """
        user_serializer = UserSerializer(data=request.data)
        if user_serializer.is_valid():
            user_serializer.save()
            return Response({'message': 'Usuario creado correctamente!'}, status=status.HTTP_201_CREATED)
        return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET', 'PUT', 'DELETE'])
def user_detail_api_view(request, pk=None):
    user = Usuario.objects.filter(id=pk).first()

    # Retrieve
    if user:
        if request.method == 'GET':
            user_serializer = UserSerializer(user)
            return Response(user_serializer.data, status=status.HTTP_200_OK)

        # Update
        elif request.method == 'PUT':
            user_serializer = UserSerializer(user, data=request.data)
            if user_serializer.is_valid():
                user_serializer.save()
                return Response(user_serializer.data, status=status.HTTP_200_OK)
            return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        # Delete
        elif request.method == 'DELETE':
            user.is_active = False
            user.save()
            return Response({'message': 'Usuario eliminado correctamente!'}, status=status.HTTP_201_CREATED)
    return Response({'message': 'Sin datos para la consulta, favor corregir y reintentar!'},
                    status=status.HTTP_400_BAD_REQUEST)


import wikipedia
import pyfiglet

word = pyfiglet.figlet_format("KAREN")
print(word)

while True:
      engine=input ("Search: ")

      def my_summary():
               summ=wikipedia.summary(engine)
               return summ
      val = my_summary()
      print(val)