"""
Module for the creation of the plots and to manage the plotWindow
"""

import os
import math
import json

import utils.globalSettings
from Classes import Verschneidung, Werkzeug
import numpy as np

from LayoutElements.matplotlib_settings import MplCanvas
from LayoutElements.matplotlib_settings import TwoDim_MplCanvas
from LayoutElements.matplotlib_settings import Polar_MplCanvas

import matplotlib
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas, NavigationToolbar2QT as NavigationToolbar
import matplotlib.backends
from matplotlib.backends import *
import matplotlib.backends.backend_pdf
import matplotlib.backends.backend_svg
from matplotlib.lines import Line2D
from matplotlib.patches import Rectangle, Circle
from matplotlib.ticker import FuncFormatter

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import matplotlib.image as image

from stl import mesh
import stl.base
from mpl_toolkits import mplot3d

import LayoutElements.mainWindowGUI as mainWindowGUI

from utils.globalSettings import (
    # Import GUI Settings to access global settings
    GUI_SETTINGS,
    # with Language Settings language pack can be accessed
    LANGUAGE_SETTINGS
)

from utils import commonFunctions

matplotlib.use('Qt5Agg')

parent_dir = os.path.dirname(__file__)
parent2_dir = os.path.dirname(os.path.dirname(__file__))

#open wataermark image for plots
WATERMARK_IMAGE_PATH= f'{parent2_dir}\\images\\Logo-PTW-TEC-min.png'
with open(WATERMARK_IMAGE_PATH,'rb') as file:
    img =image.imread(file)


#Defines names of plots for Dictionarys and Switch, DO NOT CHANGE THIS!!
LIST_PLOT_NAMES = ["Kantenvektoren", "Verschneidungen", "Kantenwinkel", "Steigungswinkel", "Drehwinkel", "Patches",
                   "Fase", "TCP_Verschneidung", "TCP_Verschneidung_transfomriert", "Werkzeug",
                   "Verschneidung_mit_Werkzeug", "plot_kollision_schaft_horizontal",
                   "plot_kollision_schaft_horizontal_2dim", "TZ_Werkzeug", "TZ_Werkzeug2",
                   "Verschneidung_mit_Werkzeug_an_tiefster_Stelle", "Normalenvektoren", "Auslegung_TZ", "Auslegung_Senkwinkel",
                   "Auslegung_Freiwinkel", "Auslegung_Kopflänge", "Auslegung_Halslänge", "Auslegung_Halsdurchmesser"]
LIST_2D_PLOTS = ["Kantenwinkel", "Steigungswinkel", "Drehwinkel", "TZ_Werkzeug", "TZ_Werkzeug2", "Auslegung_TZ",
                 "Auslegung_Senkwinkel", "Auslegung_Freiwinkel", "Auslegung_Kopflänge", "Auslegung_Halslänge", "Auslegung_Halsdurchmesser"]
LIST_POLAR_PLOTS = ["plot_kollision_schaft_horizontal_2dim"]
AUSLEGUNGS_PLOTS = ["Auslegung_TZ", "Auslegung_Senkwinkel", "Auslegung_Freiwinkel", "Auslegung_Kopflänge", "Auslegung_Halslänge", "Auslegung_Halsdurchmesser"]


#class that defines the layout of the plot window (middle part of main window=
class plotWindow(QVBoxLayout):
    """Class for the Window to show all the plots in tabs"""

    def __init__(self, mainWindow: mainWindowGUI) -> None:
        """Create the plotWindow"""
        super().__init__()

        self.ListPlotWindows = []
        self.layoutMatplot = QVBoxLayout()

        #region Plotswidget
        # Add tab widget to plot layout
        self.tabsPlot = QTabWidget()
        self.tabsPlot.setTabPosition(QTabWidget.West)
        self.tabsPlot.setMovable(True)
        self.tabsPlot.setTabsClosable(True)
        self.tabsPlot.tabCloseRequested.connect(self.closeTab)
        self.layoutMatplot.addWidget(self.tabsPlot)
        #endregion

        # Button for plot settings window
        self.buttonPlotSetting = QPushButton(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["buttonPlotSetting"])
        self.buttonPlotSetting.clicked.connect(self.showPlotEinstellungen)

        # Status indicator for settings change
        self.statusIndicator = QLabel(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["PlotStatusAktuell"])
        self.statusIndicator.setAlignment(Qt.AlignCenter)
        self.statusIndicator.setStyleSheet("background-color: green; color: white; padding: 5px;")

        # Toolbar layout for plots
        self.layoutPlotToolbar = QHBoxLayout()
        self.layoutPlotToolbar.addWidget(self.buttonPlotSetting)
        self.layoutPlotToolbar.addWidget(self.statusIndicator)

        # Layout for the entire plot window
        self.layoutPlots = QVBoxLayout()
        self.settingsPlotWindow = None

        # Get wanted plots after init --> needed for user change
        global LIST_WANTED_PLOTS
        LIST_WANTED_PLOTS = GUI_SETTINGS["DefaultPlots"]

        # Add layouts to main layout
        self.addLayout(self.layoutMatplot)
        self.addLayout(self.layoutPlotToolbar)
        self.addLayout(self.layoutPlots)

    def updateStatusIndicator(self, status):
        """Update the status indicator"""
        if status == "changed":
            self.statusIndicator.setText(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["PlotStatusNichtAktuell"])
            self.statusIndicator.setStyleSheet("background-color: #e85154; color: black; padding: 5px;")
        elif status == "warnings":
            self.statusIndicator.setText(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["PlotStatusAktuell"])
            self.statusIndicator.setStyleSheet("background-color: yellow; color: black; padding: 5px;")
        else:
            self.statusIndicator.setText(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["PlotStatusAktuell"])
            self.statusIndicator.setStyleSheet("background-color: green; color: white; padding: 5px;")

    def settingsChanged(self):
        """Method to call when settings are changed"""
        self.updateStatusIndicator("changed")

    def settingsApplied(self):
        """Method to call when settings are applied"""
        self.updateStatusIndicator("ok")

    def settingsAppliedWithWarnings(self):
        """Method to call when settings are applied"""
        self.updateStatusIndicator("warnings")

    def ExtentTabToNewWindow(self) -> None:
        """Extend the Plot to an seperate Window"""
        self.ListPlotWindows.append(WindowPlot(self))
        self.ListPlotWindows[-1].show()

    def showPlotEinstellungen(self) -> None:
        """creates and shows the window for selecting/deselcting plots"""
        if self.settingsPlotWindow is None:
            self.settingsPlotWindow = EinstellungPlotsWindow(self)
        self.settingsPlotWindow.show()

    def initPlotErstellungsButton(self, setupMenu, thisButton: QPushButton, mainWindow) -> None:
        """initializes/creates the plotErstellungsButton and gives the setupMenu and MainWindow to this class"""
        self.plotErstellungsButton = thisButton
        self.setupMenu = setupMenu
        self.mainWindow = mainWindow
        self.setConnectionsPlotErstellungsButton()

    def setConnectionsPlotErstellungsButton(self) -> None:
        """Method to connect the plot creation button with the required functions"""
        global LIST_WANTED_PLOTS

        try:
            # Disconnect any previous connections
            self.plotErstellungsButton.clicked.disconnect()
        except TypeError:
            pass  # Ignore if no connections exist initially

        # Check if LIST_WANTED_PLOTS is empty, if yes, show MsgBox
        if not LIST_WANTED_PLOTS:
            self.plotErstellungsButton.clicked.connect(lambda: QMessageBox.about(
                self.mainWindow,
                LANGUAGE_SETTINGS.languagePack["plotErstellung"]["msgBoxTitleNoPlots"],
                LANGUAGE_SETTINGS.languagePack["plotErstellung"]["msgBoxMessageNoPlots"]
            ))
            return

        # Connect initial status bar message
        self.plotErstellungsButton.clicked.connect(lambda: self.mainWindow.showStatusbarmessage(
            LANGUAGE_SETTINGS.languagePack["plotErstellung"]["StatusBarStartPlots"]
        ))

        # Prepare plots
        self.plotErstellungsButton.clicked.connect(lambda: self.preparePlots(self.setupMenu))

        # Dictionary with name of a plot and related plotErstellung object of all wanted plots to create the Tabs once the plotErstellungsButton is pressed
        self.thisPlotsDict = {}
        for namePlot in LIST_WANTED_PLOTS:
            plot_obj = plotErstellung(self.mainWindow, namePlot=namePlot)
            self.thisPlotsDict[namePlot] = plot_obj
            self.plotErstellungsButton.clicked.connect(plot_obj.plot)
            self.plotErstellungsButton.clicked.connect(plot_obj.update_canvas)

        # Create tabs after all plots are created and updated
        self.plotErstellungsButton.clicked.connect(self.createTabs)

        # Check for collisions after creating plots
        self.plotErstellungsButton.clicked.connect(lambda: VERSCHNEIDUNG_CALCULATED.checkCollision(self.mainWindow))

        # Debug: this might not be needed
        # self.plotErstellungsButton.clicked.connect(lambda: VERSCHNEIDUNG_CALCULATED.checkWarnings(self.mainWindow))

        # Reset status bar message
        self.plotErstellungsButton.clicked.connect(lambda: self.mainWindow.showStatusbarmessage(""))

    def finishInit(self) -> None:
        """method to finish the init of the plotWindow"""

        # Start Tab
        startTab = QLabel()
        pixmap = QPixmap("Images/Logo-PTW-TEC-med.png")
        startTab.setPixmap(pixmap)
        startTab.setAlignment(Qt.AlignCenter)
        self.tabsPlot.addTab(startTab, LANGUAGE_SETTINGS.languagePack["plotErstellung"]["WelcomeTabTitle"])

        # Step-by-step starter guide
        guideTab = QWidget()
        guideLayout = QVBoxLayout()

        # Add guide content as a single QLabel with HTML formatting
        guideSteps = LANGUAGE_SETTINGS.languagePack["plotErstellung"]["StarterGuide"]
        guideText = f"<h2>{LANGUAGE_SETTINGS.languagePack['plotErstellung']['GuideAllgemeineHinweise']}</h2>"
        guideText += f"<p>{LANGUAGE_SETTINGS.languagePack['plotErstellung']['GuideAllgemeineHinweiseIntro']}</p>"
        guideText += f"<h2>{LANGUAGE_SETTINGS.languagePack['plotErstellung']['GuideTabTitle']}</h2>"
        guideText += f"<p>{LANGUAGE_SETTINGS.languagePack['plotErstellung']['StarterGuideIntro']}</p>"
        for step in guideSteps:
            guideText += f"{step}<br>"

        guideLabel = QLabel(guideText)
        guideLabel.setWordWrap(True)
        guideLayout.addWidget(guideLabel)

        guideTab.setLayout(guideLayout)
        self.tabsPlot.addTab(guideTab, LANGUAGE_SETTINGS.languagePack["plotErstellung"]["GuideTabTitle"])

        # Finish layout
        self.addLayout(self.layoutPlotToolbar)
        self.addLayout(self.layoutMatplot)

    def preparePlots(self, setupMenu) -> None:
        """prepare to plot by calculating the Verschneidung object after a input checkup"""
        global VERSCHNEIDUNG_CALCULATED, WERKZEUG_CALCULATED

        #input validation
        if setupMenu.isInputPlausible(True):
            try:
                # Get the latest tool information
                geometry_data = setupMenu.generateGeometryJson()
                flag_auslegung = geometry_data["Allgemein"]["Auslegung"]
                tool_data = None
                if not flag_auslegung:
                    with open(setupMenu.selectedToolConfig["FilePath"], 'r', encoding='utf-8') as file:
                        tool_data = json.load(file)
                    tool_data["FilePath"] = setupMenu.selectedToolConfig["FilePath"]

                with open(setupMenu.selectedMachineConfig["FilePath"], 'r', encoding='utf-8') as file:
                    machine_data = json.load(file)
                process_data = setupMenu.generateProcessJson()

                VERSCHNEIDUNG_CALCULATED = Verschneidung.Verschneidung(tool_data, machine_data, geometry_data, process_data)
                VERSCHNEIDUNG_CALCULATED.checkCollision(self.mainWindow, False)
                if not flag_auslegung:
                    #VERSCHNEIDUNG_CALCULATED.checkCollision(setupMenu.mainWindow)
                    WERKZEUG_CALCULATED = Werkzeug.Werkzeug(tool_data, VERSCHNEIDUNG_CALCULATED.n_points)

            except:
                commonFunctions.showErrorMessage(self.mainWindow,
                    LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageCalc"],
                    LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageCalcDetail"])

                self.setConnectionsPlotErstellungsButton()
                self.mainWindow.showStatusbarmessage("")
                return

        else:
            self.setConnectionsPlotErstellungsButton()
            self.mainWindow.showStatusbarmessage("")
            return

        # Set Plot Status bar
        if VERSCHNEIDUNG_CALCULATED.flag_warnings:
            self.settingsAppliedWithWarnings()
        else:
            self.settingsApplied()
        print('Plot settings applied')

    def createTabs(self) -> None:
        """Creates the tabs displaying each plot"""
        global VERSCHNEIDUNG_CALCULATED
        self.tabsPlot.clear()
        for name, obj in self.thisPlotsDict.items():
            if VERSCHNEIDUNG_CALCULATED.Auslegung and name not in AUSLEGUNGS_PLOTS:
                continue
            # Create tabs
            tempTab = QWidget()
            tempTab.name = LANGUAGE_SETTINGS.languagePack["plotErstellung"]["listPlotNames"][name]
            tempTab.layout = QVBoxLayout()
            tempTab.layoutH = QHBoxLayout()
            tempTab.buttonExtend = QPushButton("")
            tempTab.buttonExtend.setIcon(QIcon('Images/ToWindow.png'))
            tempTab.buttonExtend.setToolTip(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ToolTipButtonExtend"])
            tempTab.buttonExtend.clicked.connect(self.ExtentTabToNewWindow)
            tempTab.layoutH.addWidget(tempTab.buttonExtend)

            # Add toolbar and the correct canvas
            if name in set(LIST_2D_PLOTS) - set(LIST_POLAR_PLOTS):
                tempTab.layoutH.addWidget(obj.sc2.toolbar)
                tempTab.layout.addWidget(obj.sc2)

            elif name in LIST_POLAR_PLOTS:
                tempTab.layoutH.addWidget(obj.scp.toolbar)
                tempTab.layout.addWidget(obj.scp)

            else:
                tempTab.layoutH.addWidget(obj.sc.toolbar)
                tempTab.layout.addWidget(obj.sc)

            tempTab.layout.addLayout(tempTab.layoutH)
            self.tabsPlot.addTab(tempTab, tempTab.name)
            tempTab.setLayout(tempTab.layout)

    def closeTab(self, tab_index) -> None:
        """method for closing a tab"""
        self.tabsPlot.removeTab(tab_index)

class plotErstellung:
    """class represnting one plot and its calculation"""
    def __init__(self, mainWindow, namePlot):
        super().__init__()
        self.namePlot=namePlot
        self.mainWindow = mainWindow

    def update_canvas(self):
        # Refresh the canvas
        if hasattr(self, 'sc2'):
            self.sc2.draw()
        elif hasattr(self, 'scp'):
            self.scp.draw()
        elif hasattr(self, 'sc'):
            self.sc.draw()

    @staticmethod
    def degree_formatter(x, pos):
        return f'{x:.0f}°'

    def plot(self) -> None:
        """Create the plots"""

        self.sc = MplCanvas(self.mainWindow, width=5, height=4, dpi=100)       #Matplotlib Canvas 3D
        self.sc2 = TwoDim_MplCanvas(self.mainWindow, width=5, height=4, dpi=100)  # Matplotlib Canvas 2D
        self.scp = Polar_MplCanvas(self.mainWindow, width=5, height=4, dpi=100)

        # Create separate toolbars for each canvas
        self.toolbar_sc = NavigationToolbar(self.sc, self.mainWindow)
        self.toolbar_sc2 = NavigationToolbar(self.sc2, self.mainWindow)
        self.toolbar_scp = NavigationToolbar(self.scp, self.mainWindow)
        #self.toolbar = NavigationToolbar(self.sc2, self.mainWindow)  #Toolbar von Matplotlib

        self.sc.axes.set_box_aspect(aspect=(1, 1, 1))
        self.sc.axes.set_box_aspect([ub - lb for lb, ub in (getattr(self.sc.axes, f'get_{a}lim')() for a in
                                                            'xyz')])  # notwendig, damit axis gleich skaliert u. Plots nicht verzerrt werden

        self.sc.figure.figimage(img, 0, 0, alpha=0.5, resize=False)
        self.sc2.figure.figimage(img, 0, 0, alpha=0.5, resize=False)
        self.scp.figure.figimage(img, 0, 0, alpha=0.5, resize=False)

        plot_functions = {
            "Kantenvektoren": self.plot_kantenvektoren,
            "Verschneidungen": self.plot_verschneidung,
            "Kantenwinkel": self.plot_kantenwinkel,
            "Steigungswinkel": self.plot_steigungswinkel,
            "Drehwinkel": self.plot_drehwinkel,
            "Patches": self.plot_patches,
            "Fase": self.plot_fase,
            "TCP_Verschneidung": self.plot_TCP_Verschneidung,
            "TCP_Verschneidung_transfomriert": self.plot_TCP_Verschneidung_transformed,
            "Werkzeug": self.plot_werkzeug_combined,
            "Verschneidung_mit_Werkzeug_an_tiefster_Stelle": self.plot_verschneidung_mit_werkzeug_an_tiefster_Stelle,
            "Verschneidung_mit_Werkzeug": self.plot_verschneidung_mit_werkzeug,
            "plot_kollision_schaft_horizontal_2dim": self.plot_kollision_schaft_horizontal_2dim,
            "plot_kollision_schaft_horizontal": self.plot_kollision_schaft_horizontal,
            "Normalenvektoren": self.plot_normalenvektoren,
            "TZ_Werkzeug": self.tz_werkzeug,
            "TZ_Werkzeug2": self.tz_werkzeug2,
            "Auslegung_TZ": self.plot_auslegung_tz,
            "Auslegung_Senkwinkel": self.plot_auslegung_senkwinkel,
            "Auslegung_Freiwinkel": self.plot_auslegung_freiwinkel,
            "Auslegung_Kopflänge": self.plot_auslegung_kopflaenge,
            "Auslegung_Halslänge": self.plot_auslegung_halslaenge,
            "Auslegung_Halsdurchmesser": self.plot_auslegung_halsdurchmesser
        }

        name = self.namePlot
        plot_function = plot_functions.get(name)

        if VERSCHNEIDUNG_CALCULATED.Auslegung:
            if name in AUSLEGUNGS_PLOTS:
                if plot_function:
                    print(name)
                    plot_function()
                else:
                    print("Plot function not found for", name)
            else:
                print(name, "Auslegung is True. Only Auslegung plots should be created.")
        else:
            if plot_function:
                print(name)
                plot_function()
            else:
                print("Plot function not found for", name)

    #Die restlichen Funktionen dienen zur Generierung der Plots in Matplotlib.
    #self.sc ist der Matplotlib-Canvas und wird ganz oben im Skript definiert

    def plot_normalenvektoren(self) -> None:
        self.sc.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED

        # Plot the main points
        self.sc.axes.scatter(verschneidung.x[1:-1], verschneidung.y[1:-1], verschneidung.z[1:-1], c='#009CDA',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Verschneidungspunkte"])
        # Highlight the start and end points
        self.sc.axes.scatter(verschneidung.x[0], verschneidung.y[0], verschneidung.z[0], c='green',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Startpunkt"])
        self.sc.axes.scatter(verschneidung.x[-1], verschneidung.y[-1], verschneidung.z[-1], c='red',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Endpunkt"])

        # Plot the quivers for normalenvektor
        self.sc.axes.quiver(verschneidung.x, verschneidung.y, verschneidung.z, verschneidung.normalenvektor_x,
                            verschneidung.normalenvektor_y, verschneidung.normalenvektor_z, length=0.2, color='#232E33',
                            label='Normal Vectors')

        # Set axis labels
        self.sc.axes.set_xlabel('x in mm $\\rightarrow$')
        self.sc.axes.set_ylabel('y in mm $\\rightarrow$')
        self.sc.axes.set_zlabel('z in mm $\\rightarrow$')

        # Add a legend
        self.sc.axes.legend(loc='best')

        # Set aspect ratio
        self.sc.axes.set_box_aspect([ub - lb for lb, ub in (getattr(self.sc.axes, f'get_{a}lim')() for a in 'xyz')])

        # Set a grid
        self.sc.axes.grid(True)

        # Optional: Set background color
        self.sc.figure.set_facecolor('white')

        # Adjust the axis limits
        x_min, x_max = self.sc.axes.get_xlim()
        y_min, y_max = self.sc.axes.get_ylim()
        z_min, z_max = self.sc.axes.get_zlim()

        self.sc.axes.set_xlim(x_min - 1, x_max + 1)
        self.sc.axes.set_ylim(y_min - 1, y_max + 1)
        self.sc.axes.set_zlim(z_min - 1, z_max + 1)

        # Optional: Add a color bar if relevant
        # Example for adding a color bar:
        # sc = self.sc.axes.scatter(verschneidung.x, verschneidung.y, verschneidung.z, c=verschneidung.z, cmap='viridis', label='Points', alpha=0.7)
        # self.sc.figure.colorbar(sc, ax=self.sc.axes, label='Z values')

        # Show the plot
        self.sc.draw()

    def tz_werkzeug2(self) -> None:
        tool = WERKZEUG_CALCULATED
        text_color = 'black'
        text_size = 10
        npixel_x = 492
        npixel_y = 344

        self.sc2.axes.clear()
        # Bild laden
        img = image.imread('./Images/tz_werkzeug_unbeschriftet.png')

        # Bild anzeigen
        self.sc2.axes.imshow(img)

        # Beschriftung der Pfeile im Bild erstellen
        # Durchmesser Kopf
        self.sc2.axes.text(-2 / npixel_x, 192 / npixel_y,
                           f'\u2300{round(tool.d_kopf, 3)}',
                           horizontalalignment='right',
                           verticalalignment='bottom',
                           rotation=90,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Durchmesser Schaft
        self.sc2.axes.text(280/npixel_x, 190/npixel_y,
                           f'\u2300{round(tool.d_schaft, 3)}',
                           horizontalalignment='right',
                           verticalalignment='bottom',
                           rotation=90,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Durchmesser Aufnahme
        self.sc2.axes.text(497 / npixel_x, (npixel_y-180) / npixel_y,
                           f'\u2300{round(tool.d_schaft2, 3)}',
                           horizontalalignment='left',
                           verticalalignment='center',
                           rotation=90,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Spitzenwinkel
        self.sc2.axes.text(47 / npixel_x, (npixel_y - 180) / npixel_y,
                           f'{tool.spitzenwinkel}\N{DEGREE SIGN}',
                           horizontalalignment='right',
                           verticalalignment='center',
                           rotation=90,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Gesamtlaenge
        self.sc2.axes.text(271 / npixel_x, -3 / npixel_y,
                           f'{round(tool.l_werkzeug_gesamt, 3)}',
                           horizontalalignment='center',
                           verticalalignment='top',
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Spannutlaenge
        self.sc2.axes.text(182 / npixel_x, (npixel_y - 304)  / npixel_y,
                           f'{round(tool.l_werkzeug, 3)}',
                           horizontalalignment='center',
                           verticalalignment='top',
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Laenge Aufnahme
        self.sc2.axes.text(378.5 / npixel_x, (npixel_y - 304) / npixel_y,
                           f'{round(tool.l_schaft, 3)}',
                           horizontalalignment='center',
                           verticalalignment='top',
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Laenge Kopf
        self.sc2.axes.text(110.5 / npixel_x, (npixel_y - 258) / npixel_y,
                           f'{round(tool.l_kopf, 3)}',
                           horizontalalignment='center',
                           verticalalignment='top',
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Senkwinkel
        self.sc2.axes.text(99 / npixel_x, (npixel_y - 148) / npixel_y,
                           f'{tool.schneidenwinkel}\N{DEGREE SIGN}',
                           horizontalalignment='left',
                           verticalalignment='bottom',
                           rotation=55,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Freiwinkel
        self.sc2.axes.text(-75 / npixel_x, (npixel_y - 240) / npixel_y,
                           f'Hinter-\nschliff {tool.freiwinkel}\N{DEGREE SIGN}',
                           horizontalalignment='left',
                           verticalalignment='top',
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Ausrichtung Schneide
        self.sc2.axes.text(360 / npixel_x, (npixel_y + 5) / npixel_y,
                           f'Ausrichtung der \nHB-Fläche {tool.winkeloffset}\N{DEGREE SIGN}\nzur Senkschneide ',
                           horizontalalignment='left',
                           verticalalignment='top',
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)


        # Achsen deaktivieren
        self.sc2.axes.axis('off')
        self.sc2.axes.set_aspect('equal')

    def tz_werkzeug(self) -> None:

        tool = WERKZEUG_CALCULATED
        from matplotlib.path import Path
        from matplotlib.patches import PathPatch
        text_color = 'black'
        text_size = 10

        self.sc2.axes.clear()

        center = [50, 0]  # Koord. Spitze Werkzeug

        # Größe d. Plots
        ax_lim_x = 70 + tool.d_kopf
        ax_lim_y = tool.l_werkzeug_gesamt + 10
        y_lim = -5  #untere Grenze y-Achse

        # Eckpunkte

        l1 = [center[0] - tool.d_kopf * 0.5, center[1] + tool.h_spitze]
        r1 = [center[0] + tool.d_kopf * 0.5, center[1] + tool.h_spitze]

        l2 = [center[0] - tool.d_kopf * 0.5, center[1] + tool.h_kopf]
        r2 = [center[0] + tool.d_kopf * 0.5, center[1] + tool.h_kopf]

        l3 = [center[0] - tool.d_schaft * 0.5, center[1] + tool.h_schneide]
        r3 = [center[0] + tool.d_schaft * 0.5, center[1] + tool.h_schneide]

        l4 = [center[0] - tool.d_schaft * 0.5, center[1] + tool.l_werkzeug]
        r4 = [center[0] + tool.d_schaft * 0.5, center[1] + tool.l_werkzeug]

        l5 = [center[0] - tool.d_schaft2 * 0.5, center[1] + tool.l_werkzeug_gesamt - tool.l_schaft]
        r5 = [center[0] + tool.d_schaft2 * 0.5, center[1] + tool.l_werkzeug_gesamt - tool.l_schaft]

        l6 = [center[0] - tool.d_schaft2 * 0.5, center[1] + tool.l_werkzeug_gesamt]
        r6 = [center[0] + tool.d_schaft2 * 0.5, center[1] + tool.l_werkzeug_gesamt]

        arrow_color = 'black'  # Color of the arrow
        arrow_width = 0.02  # Width of the arrow
        head_w = 0.5

        # Arrow Gesamtlänge
        self.sc2.axes.arrow(5, center[1], 0, tool.l_werkzeug_gesamt - 2, color=arrow_color, width=arrow_width, head_length=2,
                            head_width=head_w)
        self.sc2.axes.arrow(5, center[1] + l6[1], 0, -(tool.l_werkzeug_gesamt - 2), color=arrow_color, width=arrow_width,
                            head_length=2, head_width=head_w)

        # Arrow Werkzeuglänge

        self.sc2.axes.arrow(10, center[1], 0, tool.l_werkzeug - 2, color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)
        self.sc2.axes.arrow(10, center[1]+l4[1], 0, -(tool.l_werkzeug - 2), color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)

        # Arrow Schaftlänge

        self.sc2.axes.arrow(10, l5[1], 0, tool.l_schaft - 2, color=arrow_color, width=arrow_width, head_length=2,
                            head_width=head_w)
        self.sc2.axes.arrow(10, l6[1], 0, -(tool.l_schaft - 2), color=arrow_color, width=arrow_width,
                            head_length=2, head_width=head_w)

        # Arrow Höhe Schneide

        self.sc2.axes.arrow(15, center[1], 0, tool.h_schneide - 2, color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)
        self.sc2.axes.arrow(15, center[1]+tool.h_schneide, 0, -(tool.h_schneide - 2), color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)

        # Arrow Höhe Kopf

        self.sc2.axes.arrow(20, center[1], 0, tool.h_kopf - 2, color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)
        self.sc2.axes.arrow(20, center[1]+tool.h_kopf, 0, -(tool.h_kopf - 2), color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)

        # Arrow Höhe Spitze

        self.sc2.axes.arrow(25, center[1]-3-2, 0, 3, color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)
        self.sc2.axes.arrow(25, center[1]+tool.h_spitze+3+2, 0, -3, color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)

        # Arrow Durchmesser Kopf

        self.sc2.axes.arrow(center[0]-tool.d_kopf*0.5-5, center[1]-3, 3, 0, color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)
        self.sc2.axes.arrow(center[0] + tool.d_kopf * 0.5 + 5, center[1] - 3, -3, 0, color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)

        # Arrow Durchmesser Schaft

        self.sc2.axes.arrow(l3[0] - 5, (l3[1]+l4[1])*0.5, 3, 0, color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)
        self.sc2.axes.arrow(r3[0] + 5, (r3[1] + r4[1]) * 0.5, -3, 0, color=arrow_color, width=arrow_width, head_length=2, head_width=head_w)

        # untere Maßhilfslinie

        self.sc2.axes.axhline(y=center[1], xmin=2.5 / ax_lim_x, xmax=center[0] / ax_lim_x, color='black', linestyle='-', linewidth='0.5')

        # Maßhilfslinie Spannutlänge

        self.sc2.axes.axhline(y=center[1] + l4[1], xmin=7.5 / ax_lim_x, xmax=l4[0] / ax_lim_x, color='black', linestyle='-', linewidth='0.5')

        # Maßhilfslinie Gesamtlänge
        self.sc2.axes.axhline(y=center[1] + l6[1], xmin=2.5 / ax_lim_x, xmax=l6[0] / ax_lim_x, color='black', linestyle='-', linewidth='0.5')

        # Maßhilfslinie Schaflänge
        self.sc2.axes.axhline(y=center[1] + l5[1], xmin=7.5 / ax_lim_x, xmax=l5[0] / ax_lim_x, color='black', linestyle='-', linewidth='0.5')

        # Maßhilfslinie Höhe Schneide

        self.sc2.axes.axhline(y=center[1]+tool.h_schneide, xmin=12.5 / ax_lim_x, xmax=l3[0] / ax_lim_x, color='black', linestyle='-', linewidth='0.5')

        # Maßhilfslinie Höhe Kopf
        self.sc2.axes.axhline(y=center[1]+tool.h_kopf, xmin=17.5 / ax_lim_x, xmax=l2[0] / ax_lim_x, color='black', linestyle='-', linewidth='0.5')

        # Maßhilfslinie Spitzenlänge
        self.sc2.axes.axhline(y=center[1]+tool.h_spitze, xmin=22.5 / ax_lim_x, xmax=l1[0] / ax_lim_x, color='black', linestyle='-', linewidth='0.5')

        # Maßhilfslinie Durchmesser Kopf
        self.sc2.axes.axvline(x=center[0] - tool.d_kopf * 0.5, ymin=0, ymax=(-y_lim + center[1] + tool.h_spitze)/ax_lim_y, color='black', linestyle='-', linewidth=0.5)
        self.sc2.axes.axvline(x=center[0] + tool.d_kopf * 0.5, ymin=0, ymax=(-y_lim + center[1] + tool.h_spitze) / ax_lim_y, color='black', linestyle='-', linewidth=0.5)

        # Beschriftungen


        self.sc2.axes.text((10 / ax_lim_x) - 0.02 , (0.5 * tool.l_werkzeug - y_lim)/ (ax_lim_y - y_lim), f'{round(tool.l_werkzeug, 3)}',
                           horizontalalignment='center',
                           verticalalignment='center',
                           rotation=90,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold')

        self.sc2.axes.text((10 / ax_lim_x) - 0.02, (tool.l_werkzeug_gesamt - 0.5 * tool.l_schaft - y_lim) / (ax_lim_y - y_lim),
                           f'{round(tool.l_schaft, 3)}',
                           horizontalalignment='center',
                           verticalalignment='center',
                           rotation=90,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold')

        self.sc2.axes.text((5 / ax_lim_x) - 0.02, (0.5 * tool.l_werkzeug_gesamt - y_lim) / (ax_lim_y - y_lim),
                           f'{round(tool.l_werkzeug_gesamt, 3)}',
                           horizontalalignment='center',
                           verticalalignment='center',
                           rotation=90,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold')

        self.sc2.axes.text((20 / ax_lim_x) - 0.02, (0.5 * tool.h_kopf - y_lim) / (ax_lim_y - y_lim), f'{round(tool.h_kopf, 3)}',
                           horizontalalignment='center',
                           verticalalignment='center',
                           rotation=90,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold')

        self.sc2.axes.text((15 / ax_lim_x) - 0.02, (0.5 * tool.h_schneide- y_lim) / (ax_lim_y - y_lim), f'{round(tool.h_schneide, 3)}',
                           horizontalalignment='center',
                           verticalalignment='center',
                           rotation=90,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold')

        self.sc2.axes.text((25 / ax_lim_x) - 0.02, (0.5*3+tool.h_spitze-y_lim + tool.h_spitze)/ (ax_lim_y - y_lim), f'{round(tool.h_spitze,3)}',
                 horizontalalignment='center',
                 verticalalignment='center',
                 rotation=90,
                 transform=self.sc2.axes.transAxes,
                           fontweight='bold')

        self.sc2.axes.text(((center[0] + tool.d_kopf * 0.5 + 2) / ax_lim_x), (0.15 * ( -y_lim)) / (ax_lim_y - y_lim),
                           f'\u2300{round(tool.d_kopf, 3)}',
                           horizontalalignment='left',
                           verticalalignment='center',
                           rotation=0,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold')

        self.sc2.axes.text(((r3[0] + 2) / ax_lim_x), (-y_lim + (r3[1]+r4[1]) * 0.5)/ (ax_lim_y - y_lim),
                           f'\u2300{round(tool.d_schaft, 3)}',
                           horizontalalignment='left',
                           verticalalignment='bottom',
                           rotation=0,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold')

        kontur_x = [l6[0], l5[0], l4[0], l3[0], l2[0], l1[0], center[0], r1[0], r2[0], r3[0], r4[0], r5[0], r6[0], l6[0]]
        kontur_y = [l6[1], l5[1], l4[1], l3[1], l2[1], l1[1], center[1], r1[1], r2[1], r3[1], r4[1], r5[1], r6[1], l6[1]]

        self.sc2.axes.plot(kontur_x, kontur_y, color = 'black')


        #Schräge Maßhilfslinie für Schneidenwinkel

        #self.sc2.axes.plot([r2[0],r2[0]+2],[r2[1],r2[1]-2], color = 'black', linewidth='0.5')
        dx = (3 * tool.d_kopf / 4.0) * np.cos(np.radians(tool.schneidenwinkel) + (3 * np.pi / 2.0))
        dy = (3 * tool.d_kopf / 4.0) * np.sin(np.radians(tool.schneidenwinkel) + (3 * np.pi / 2.0))
        self.sc2.axes.plot([r2[0], r2[0] + dx], [r2[1], r2[1] + dy], color='black', linewidth='0.5')

        self.sc2.axes.text(((r2[0] + dx) / ax_lim_x), (-y_lim + r2[1] + 0.25 * dy) / (ax_lim_y - y_lim),
                           f'{tool.schneidenwinkel}\N{DEGREE SIGN}',
                           horizontalalignment='left',
                           verticalalignment='center',
                           rotation=0,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold')

        # Winkel in Bogenmaß umrechnen
        theta = np.linspace(0, np.radians(tool.schneidenwinkel), 20)
        theta = theta - (np.pi / 2.0)

        # Kreissegment
        x_kreis_schneidenwinkel = (tool.d_kopf / 2.0) * np.cos(theta)
        y_kreis_schneidenwinkel = (tool.d_kopf / 2.0) * np.sin(theta)

        # Kreis an richtige Stelle schieben
        x_kreis_schneidenwinkel = x_kreis_schneidenwinkel + r2[0]
        y_kreis_schneidenwinkel = y_kreis_schneidenwinkel + r2[1]

        # Plot Kreissegment
        self.sc2.axes.plot(x_kreis_schneidenwinkel, y_kreis_schneidenwinkel, color='black', linewidth='0.8')

        # Pfeil links
        x_arrow = x_kreis_schneidenwinkel[0]
        y_arrow = y_kreis_schneidenwinkel[0]

        dx_arrow = x_kreis_schneidenwinkel[1] - x_kreis_schneidenwinkel[0]
        dy_arrow = y_kreis_schneidenwinkel[1] - y_kreis_schneidenwinkel[0]
        self.sc2.axes.arrow(x_arrow, y_arrow, dx_arrow, dy_arrow, color=arrow_color, width=arrow_width, head_length=2,
                            head_width=head_w, length_includes_head=True)

        # Pfeil rechts
        x_arrow = x_kreis_schneidenwinkel[-1]
        y_arrow = y_kreis_schneidenwinkel[-1]

        dx_arrow = x_kreis_schneidenwinkel[-2] - x_kreis_schneidenwinkel[-1]
        dy_arrow = y_kreis_schneidenwinkel[-2] - y_kreis_schneidenwinkel[-1]
        self.sc2.axes.arrow(x_arrow, y_arrow, dx_arrow, dy_arrow, color=arrow_color, width=arrow_width, head_length=2,
                            head_width=head_w, length_includes_head=True)

        # Plot Hilfslinien
        self.sc2.axes.plot([center[0], center[0] - tool.d_kopf * 3 / 8], [center[1], center[1] - tool.h_spitze * 3 / 8],
                           color='black', linewidth='0.5')
        self.sc2.axes.plot([center[0], center[0] + tool.d_kopf * 3 / 8], [center[1], center[1] - tool.h_spitze * 3 / 8],
                           color='black', linewidth='0.5')



        #Spitzenwinkel Maßhilfslinien

        text2 = f'{tool.spitzenwinkel}\N{DEGREE SIGN}'
        text_object = self.sc2.axes.text(0, 0, text2, color=text_color, horizontalalignment='center', fontsize=text_size, fontweight='bold')
        text_object.set_position((center[0], center[1]-tool.d_kopf/2))

        # Winkel in Bogenmaß umrechnen
        theta = np.linspace(0, np.radians(tool.spitzenwinkel), 20)
        theta = theta - (np.pi / 2.0) - np.radians(tool.spitzenwinkel / 2)

        # Kreissegment
        x_kreis_schneidenwinkel = (tool.d_kopf / 4.0) * np.cos(theta)
        y_kreis_schneidenwinkel = (tool.d_kopf / 4.0) * np.sin(theta)

        # Kreis an richtige Stelle schieben
        x_kreis_schneidenwinkel = x_kreis_schneidenwinkel + center[0]
        y_kreis_schneidenwinkel = y_kreis_schneidenwinkel + center[1]

        # Plot Kreissegment
        self.sc2.axes.plot(x_kreis_schneidenwinkel, y_kreis_schneidenwinkel, color='black', linewidth='0.8')

        # Pfeil links
        x_arrow = x_kreis_schneidenwinkel[1]
        y_arrow = y_kreis_schneidenwinkel[1]

        dx_arrow = x_kreis_schneidenwinkel[0] - x_kreis_schneidenwinkel[1]
        dy_arrow = y_kreis_schneidenwinkel[0] - y_kreis_schneidenwinkel[1]
        self.sc2.axes.arrow(x_arrow, y_arrow, dx_arrow, dy_arrow, color=arrow_color, width=arrow_width, head_length=0.5,
                            head_width=head_w, length_includes_head=True)

        # Pfeil rechts
        x_arrow = x_kreis_schneidenwinkel[-2]
        y_arrow = y_kreis_schneidenwinkel[-2]

        dx_arrow = x_kreis_schneidenwinkel[-1] - x_kreis_schneidenwinkel[-2]
        dy_arrow = y_kreis_schneidenwinkel[-1] - y_kreis_schneidenwinkel[-2]
        self.sc2.axes.arrow(x_arrow, y_arrow, dx_arrow, dy_arrow, color=arrow_color, width=arrow_width, head_length=0.5,
                            head_width=head_w, length_includes_head=True)

        # Plot Hilfslinien
        self.sc2.axes.plot([center[0], center[0] - tool.d_kopf * 3 / 8], [center[1], center[1] - tool.h_spitze * 3 / 8], color='black', linewidth='0.5')
        self.sc2.axes.plot([center[0], center[0] + tool.d_kopf * 3 / 8], [center[1], center[1] - tool.h_spitze * 3 / 8], color='black', linewidth='0.5')

        #Symmetrieachse

        self.sc2.axes.plot([center[0], center[0]], [center[1]-5, center[1]+l6[1]+5], color='black', linestyle='-.')


        self.sc2.axes.set_xlim(0, ax_lim_x)
        self.sc2.axes.set_ylim(y_lim, ax_lim_y)

        self.sc2.axes.set_xticks([])
        self.sc2.axes.set_yticks([])
        self.sc2.axes.set_aspect('equal')
        self.sc2.axes.axis('off')

    def plot_kollision_schaft_horizontal(self) -> None:

        self.sc.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED
        tool = WERKZEUG_CALCULATED

        axes = plt.figure().add_subplot(projection='3d')

        xqb, yqb, zqb = Verschneidung.data_for_cylinder_along_z(0.0, verschneidung.av, verschneidung.d_qb / 2.0,
                                                                -verschneidung.d_qb,
                                                                verschneidung.d_qb)

        self.sc.axes.scatter(verschneidung.x, verschneidung.y, verschneidung.z, facecolor='gray', edgecolor='gray')

        if verschneidung.ebener_Austritt:
            # Plot a flat plane for the second cylinder
            xhb, yhb = np.meshgrid(np.linspace(-verschneidung.d_hb / 2.0, verschneidung.d_hb / 2.0, 30),
                                   np.linspace(-verschneidung.d_hb / 2.0, verschneidung.d_hb / 2.0, 30))
            zhb = np.full_like(xhb, 0.0)
            self.sc.axes.plot_surface(xhb, yhb, zhb, color='grey', alpha=0.3)
        else:
            zhb, yhb, xhb = Verschneidung.data_for_cylinder_along_z(0.0, 0.0, verschneidung.d_hb / 2.0, -30.0, 30.0)
            self.sc.axes.plot_surface(xhb, yhb, zhb, color='grey', alpha=0.3)

            # Set cylinder for Querbohrung higher
            zqb += verschneidung.d_hb / 2.0

        self.sc.axes.plot_surface(xqb, yqb, zqb, color='grey', alpha=0.3)

        r_schaft = tool.d_schaft * 0.5

        d_qb = verschneidung.d_qb
        r_qb = d_qb * 0.5

        #Achtung: abstand_sicherheit wurde hier manuell festgelegt und wird noch in settings ergänzt

        abstand_sicherheit = GUI_SETTINGS["safteyTolerance"]

        x_pkte_außerhalb_tol = []
        y_pkte_außerhalb_tol = []
        z_pkte_außerhalb_tol = []

        x_pkte_innerhalb_tol = []
        y_pkte_innerhalb_tol = []
        z_pkte_innerhalb_tol = []

        r_tcp = np.hypot(verschneidung.tcp_x, verschneidung.tcp_y)
        phi = np.arctan2(verschneidung.tcp_y, verschneidung.tcp_x) * 180 / np.pi

        for i in range(verschneidung.n_points):

            # Kollision

            if r_tcp[i] > ((r_qb + verschneidung.av) - r_schaft - abstand_sicherheit):
                x_pkte_außerhalb_tol.append(verschneidung.tcp_x[i])
                y_pkte_außerhalb_tol.append(verschneidung.tcp_y[i])
                z_pkte_außerhalb_tol.append(verschneidung.tcp_z[i])

            elif r_tcp[i] < ((r_qb + verschneidung.av) - r_schaft - abstand_sicherheit):
                x_pkte_innerhalb_tol.append(verschneidung.tcp_x[i])
                y_pkte_innerhalb_tol.append(verschneidung.tcp_y[i])
                z_pkte_innerhalb_tol.append(verschneidung.tcp_z[i])

        #self.sc.axes.set_xlim(min(verschneidung.x), max(verschneidung.x))
        #self.sc.axes.set_ylim(min(verschneidung.y), max(verschneidung.y))

        self.sc.axes.set_xlabel('x in mm $\\rightarrow$')
        self.sc.axes.set_ylabel('y in mm $\\rightarrow$')
        self.sc.axes.set_zlabel('z in mm $\\rightarrow$')

        self.sc.axes.scatter(x_pkte_außerhalb_tol, y_pkte_außerhalb_tol, z_pkte_außerhalb_tol, facecolor='red', edgecolor='red')
        self.sc.axes.scatter(x_pkte_innerhalb_tol, y_pkte_innerhalb_tol, z_pkte_innerhalb_tol, facecolor='green', edgecolor='green')

        custom_lines = [Line2D([0], [0], color="tab:green", lw=4),
                        Line2D([0], [0], color="tab:red", lw=4)]
        self.sc.axes.legend(custom_lines, [LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Collision3DLegend1"], LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Collision3DLegend2"]], loc="lower right", bbox_to_anchor=(1,1))

        self.sc.axes.set_box_aspect(aspect=(1, 1, 1))
        self.sc.axes.set_box_aspect([ub - lb for lb, ub in (getattr(self.sc.axes, f'get_{a}lim')() for a in 'xyz')])

    def plot_kollision_schaft_horizontal_2dim(self) -> None:
        self.scp.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED
        tool = WERKZEUG_CALCULATED

        d_qb = verschneidung.d_qb
        r_qb = d_qb * 0.5

        r_tcp = np.hypot(verschneidung.tcp_x, verschneidung.tcp_y)

        phi = np.arctan2(verschneidung.tcp_y, verschneidung.tcp_x)

        phi2 = [0] * len(phi)
        phi3 = [0] * len(phi)
        tcp_y_av = [0] * len(phi)

        for i in range(len(r_tcp)):
            tcp_y_av[i] = verschneidung.tcp_y[i] - verschneidung.av

        phi2 = np.arctan2(tcp_y_av, verschneidung.tcp_x)

        r_tcp_schaft = [0] * len(r_tcp)
        tcp_schaft_x = [0] * len(r_tcp)
        tcp_schaft_y = [0] * len(r_tcp)

        r_bohrung = [0] * 150
        bohrung_x = [0] * 150
        bohrung_y = [0] * 150

        beta = [0] * 150

        for i in range(len(r_tcp)):
            tcp_schaft_x[i] = verschneidung.tcp_x[i] + (tool.d_schaft * 0.5) * np.cos(phi2[i])
            tcp_schaft_y[i] = verschneidung.tcp_y[i] + (tool.d_schaft * 0.5) * np.sin(phi2[i])

        phi3 = np.arctan2(tcp_schaft_y, tcp_schaft_x)
        r_tcp_schaft = np.hypot(tcp_schaft_x, tcp_schaft_y)

        phi3 = np.append(phi3, phi3[0])
        r_tcp_schaft = np.append(r_tcp_schaft, r_tcp_schaft[0])

        t = np.arange(0, 150, 1)
        theta = 2 * np.pi * t * 1 / 150

        for i in range(len(theta)):
            bohrung_x[i] = r_qb * np.cos(theta[i])
            bohrung_y[i] = verschneidung.av + r_qb * np.sin(theta[i])

        r_bohrung = np.hypot(bohrung_x, bohrung_y)
        beta = np.arctan2(bohrung_y, bohrung_x)

        beta = np.append(beta, beta[0])
        r_bohrung = np.append(r_bohrung, r_bohrung[0])
        phi3 = np.append(phi3, phi3[0])
        r_tcp_schaft = np.append(r_tcp_schaft, r_tcp_schaft[0])
        phi = np.append(phi, phi[0])
        r_tcp = np.append(r_tcp, r_tcp[0])

        self.scp.axes.plot(beta, r_bohrung, color="black",
                           label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Collision2DLegend1"])
        self.scp.axes.plot(phi3, r_tcp_schaft, color="tab:blue",
                           label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Collision2DLegend2"])
        self.scp.axes.plot(phi, r_tcp, color="tab:orange", lw=1,
                           label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Collision2DLegend3"])

        # Calculate the maximum radius for scaling
        max_radius = max(np.max(r_bohrung), np.max(r_tcp_schaft), np.max(r_tcp))

        # Set the r-axis limit to 120% of the largest radius
        self.scp.axes.set_rmax(max_radius * 1.5)

        self.scp.axes.set_rticks(np.arange(0.5, max_radius * 1.2, 1))
        self.scp.axes.set_rlabel_position(-22.5)
        self.scp.axes.grid(True)

        self.scp.axes.legend(loc='upper right', bbox_to_anchor=(1.15, 1.2))

        plt.tight_layout()

    def plot_kantenvektoren(self) -> None:

        self.sc.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED
        self.sc.axes.scatter(verschneidung.x, verschneidung.y, verschneidung.z, c='#009CDA',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Verschneidungspunkte"])

        self.sc.axes.quiver(verschneidung.x, verschneidung.y, verschneidung.z, verschneidung.kantenvektor_hb_x,
                            verschneidung.kantenvektor_hb_y, verschneidung.kantenvektor_hb_z,
                            label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Hauptbohrungsvektor"],
                            color="#4E4E4E")
        self.sc.axes.quiver(verschneidung.x, verschneidung.y, verschneidung.z, verschneidung.kantenvektor_qb_x,
                            verschneidung.kantenvektor_qb_y, verschneidung.kantenvektor_qb_z,
                            label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Querbohrungsvektor"],
                            color="#000000")

        self.sc.axes.set_xlabel('x in mm $\\rightarrow$')
        self.sc.axes.set_ylabel('y in mm $\\rightarrow$')
        self.sc.axes.set_zlabel('z in mm $\\rightarrow$')

        self.sc.axes.set_xlim(min(verschneidung.x) - 2, max(verschneidung.x) + 2)
        self.sc.axes.set_ylim(min(verschneidung.y) - 2, max(verschneidung.y) + 2)
        self.sc.axes.set_zlim(min(verschneidung.z) - 2, max(verschneidung.z) + 2)

        # Add a legend
        self.sc.axes.legend(loc='best')

        # notwendig, damit axis gleich skaliert u. Plots nicht verzerrt werden:
        self.sc.axes.set_box_aspect(aspect=(1, 1, 1))
        self.sc.axes.set_box_aspect([ub - lb for lb, ub in (getattr(self.sc.axes, f'get_{a}lim')() for a in 'xyz')])

        self.sc.draw()

    def plot_steigungswinkel(self) -> None:
        self.sc2.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED
        tool = WERKZEUG_CALCULATED

        # Plot numerically calculated inclination angles
        self.sc2.axes.scatter(
            verschneidung.omega_deg, verschneidung.steigungswinkel_num, c='#009CDA', marker='o',
            label="Numerisch"
        )

        # Plot analytically calculated inclination angles
        self.sc2.axes.scatter(
            verschneidung.omega_deg, verschneidung.steigungswinkel_ana, c='#00517F', marker='o',
            label="Analytisch"
        )

        # Plot points above critical value in red
        critical_indices_ana = [i for i, val in enumerate(verschneidung.steigungswinkel_ana) if val > tool.freiwinkel]
        if len(critical_indices_ana) > 0:
            self.sc2.axes.scatter([verschneidung.omega_deg[i] for i in critical_indices_ana],
                                  [verschneidung.steigungswinkel_ana[i] for i in critical_indices_ana],
                                  c='red', marker='o', label="Kritisch")

        critical_indices_num = [i for i, val in enumerate(verschneidung.steigungswinkel_num) if val > tool.freiwinkel]
        if len(critical_indices_num) > 0:
            self.sc2.axes.scatter([verschneidung.omega_deg[i] for i in critical_indices_num],
                                  [verschneidung.steigungswinkel_num[i] for i in critical_indices_num],
                                  c='red', marker='o')

        # Plot angle limit line
        self.sc2.axes.axhline(y=tool.freiwinkel, color='black', linestyle='--')

        self.sc2.axes.set_xlabel(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Positionnr"])
        self.sc2.axes.set_ylabel(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle3"])

        # Get the limits of the plot
        x_min, x_max = self.sc2.axes.get_xlim()
        y_min, y_max = self.sc2.axes.get_ylim()

        # Fill area below angle limit line (allowed area)
        self.sc2.axes.fill_between([x_min, x_max], tool.freiwinkel, y_min, color='green', alpha=0.1)

        # Add text label at the axhline
        text = f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["MaxBearbeitbarerSteigungswinkel"]}: {round(tool.freiwinkel)}\N{DEGREE SIGN}'
        self.sc2.axes.text(x_min + (x_max - x_min) * 0.5, tool.freiwinkel * 1.01, text, va="bottom", ha="center")

        # Set the x-limits and y-limits of the plot to prevent resizing
        max_ana = max(verschneidung.steigungswinkel_ana)
        max_num = max(verschneidung.steigungswinkel_num)
        max_total = max([max_ana, max_num, tool.freiwinkel])

        self.sc2.axes.set_xlim(0, 360)
        self.sc2.axes.set_ylim(y_min, max_total * 1.5)

        self.sc2.axes.set_xlabel(
            f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Winkelparameter"]} $\\rightarrow$')
        self.sc2.axes.set_ylabel(f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle3"]} $\\rightarrow$')

        # Apply the custom formatter to add the degree symbol
        self.sc2.axes.yaxis.set_major_formatter(FuncFormatter(self.degree_formatter))
        self.sc2.axes.xaxis.set_major_formatter(FuncFormatter(self.degree_formatter))

        # Manually set x-axis ticks from 0 to 360 degrees
        self.sc2.axes.set_xticks(range(0, 361, 60))
        self.sc2.axes.set_xticklabels([f'{i}°' for i in range(0, 361, 60)])

        # Improve the appearance of the grid
        self.sc2.axes.grid(True, which='both', linestyle='--', linewidth=0.5)

        # Create a secondary y-axis for Freiwinkel
        ax2 = self.sc2.axes.twinx()

        # Set the same y-limits as the primary y-axis
        ax2.set_ylim(self.sc2.axes.get_ylim())
        ax2.set_ylabel(f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle4"]} $\\rightarrow$', color='green')

        # Apply the custom formatter to add the degree symbol
        ax2.yaxis.set_major_formatter(FuncFormatter(self.degree_formatter))

        # Set the color of the right y-axis
        ax2.spines['right'].set_color('green')
        ax2.tick_params(axis='y', colors='green')
        ax2.yaxis.label.set_color('green')

        # Add a legend with a better placement
        self.sc2.axes.legend(loc='best')

        # Adjust the layout to make room for the labels and title
        plt.tight_layout()

    def plot_verschneidung(self) -> None:

        self.sc.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED

        if verschneidung.ebener_Austritt:
            x = np.linspace(verschneidung.transf_transl_x - verschneidung.d_qb, verschneidung.transf_transl_x + verschneidung.d_qb, 10)
            y = np.linspace(verschneidung.transf_transl_y - verschneidung.d_qb, verschneidung.transf_transl_y + verschneidung.d_qb, 10)
            xhb, yhb = np.meshgrid(x, y)
            zhb = np.ones_like(xhb) * verschneidung.transf_transl_z
            self.sc.axes.plot_surface(xhb, yhb, zhb, color='grey', alpha=0.3)
        else:
            # Plot cylinders
            zhb1, yhb1, xhb1 = Verschneidung.data_for_cylinder_along_z(0, 0, verschneidung.d_hb / 2.0, -(verschneidung.d_hb / 2.0), verschneidung.d_hb / 2.0)
            xhb, yhb, zhb = Verschneidung.rotate_cylinder(xhb1, yhb1, zhb1, verschneidung.phi, verschneidung.theta, verschneidung.psi)
            xhb += verschneidung.transf_transl_x
            yhb += verschneidung.transf_transl_y
            zhb += verschneidung.transf_transl_z
            self.sc.axes.plot_surface(xhb, yhb, zhb, color='grey', alpha=0.3)


        av = verschneidung.av
        trans_d_db = verschneidung.d_hb / 2.0
        if verschneidung.ebener_Austritt:
            av = 0
            trans_d_db = 0

        xqb1, yqb1, zqb1 = Verschneidung.data_for_cylinder_along_z(0, av, verschneidung.d_qb / 2.0, -(verschneidung.d_qb / 2.0), verschneidung.d_qb / 2.0)
        xqb, yqb, zqb = Verschneidung.rotate_cylinder(xqb1, yqb1, zqb1, verschneidung.phi, verschneidung.theta, verschneidung.psi)
        xqb += verschneidung.transf_transl_x
        yqb += verschneidung.transf_transl_y
        zqb += verschneidung.transf_transl_z + trans_d_db

        self.sc.axes.plot_surface(xqb, yqb, zqb, color='grey', alpha=0.3)

        self.sc.axes.set_xlabel('x in mm $\\rightarrow$')
        self.sc.axes.set_ylabel('y in mm $\\rightarrow$')
        self.sc.axes.set_zlabel('z in mm $\\rightarrow$')

        # Plot the main points
        self.sc.axes.scatter(verschneidung.translated_x[1:-1], verschneidung.translated_y[1:-1], verschneidung.translated_z[1:-1], c='#009CDA',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Verschneidungspunkte"])
        # Highlight the start and end points
        self.sc.axes.scatter(verschneidung.translated_x[0], verschneidung.translated_y[0], verschneidung.translated_z[0], c='green',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Startpunkt"])
        self.sc.axes.scatter(verschneidung.translated_x[-1], verschneidung.translated_y[-1], verschneidung.translated_z[-1], c='red',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Endpunkt"])

        # Get axis limits
        max_x = max(max(np.max(xqb), np.max(xhb)), max(verschneidung.translated_x))
        min_x = min(min(np.min(xqb), np.min(xhb)), min(verschneidung.translated_x))
        max_y = max(max(np.max(yqb), np.max(yhb)), max(verschneidung.translated_y))
        min_y = min(min(np.min(yqb), np.min(yhb)), min(verschneidung.translated_y))
        max_z = max(max(np.max(zqb), np.max(zhb)), max(verschneidung.translated_z))
        min_z = min(min(np.min(zqb), np.min(zhb)), min(verschneidung.translated_z))

        self.sc.axes.set_xlim(min_x - 2, max_x + 2)
        self.sc.axes.set_ylim(min_y - 2, max_y + 2)
        self.sc.axes.set_zlim(min_z - 2, max_z + 2)

        self.sc.axes.set_box_aspect(aspect=(1, 1, 1))
        self.sc.axes.set_box_aspect([ub - lb for lb, ub in (getattr(self.sc.axes, f'get_{a}lim')() for a in 'xyz')])

        # Add a legend with a better placement
        self.sc.axes.legend(loc='best')

    def plot_kantenwinkel(self) -> None:
        self.sc2.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED
        tool = WERKZEUG_CALCULATED

        # Plot numerically calculated inclination angles
        self.sc2.axes.scatter(
            verschneidung.omega_deg, verschneidung.kantenwinkel, c='#009CDA', marker='o',
            label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle2"]
        )

        # Get the limits of the plot
        x_min, x_max = self.sc2.axes.get_xlim()

        max_allowed_angle = 180.0 - tool.schneidenwinkel
        # Plot angle limit line
        self.sc2.axes.axhline(y=max_allowed_angle, linestyle='--', color='black')
        # Fill area below angle limit line (allowed area)
        self.sc2.axes.fill_between([x_min, x_max], max_allowed_angle, 0, color='green', alpha=0.1)

        # Add text label at the axhline
        text = f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["MaxBearbeitbarerKantenwinkel"]}: {round(max_allowed_angle)}\N{DEGREE SIGN}'
        self.sc2.axes.text(x_min + (x_max - x_min) * 0.5, max_allowed_angle * 1.01, text, va="bottom",
                           ha="center")

        # Plot points above critical value in red
        critical_indices = [i for i, val in enumerate(verschneidung.kantenwinkel) if val > max_allowed_angle]
        if len(critical_indices) > 0:
            self.sc2.axes.scatter([verschneidung.omega_deg[i] for i in critical_indices],
                                  [verschneidung.kantenwinkel[i] for i in critical_indices],
                                  c='red', marker='o', label="Kritische Punkte")

        # Set the x-limits and y-limits of the plot to prevent resizing
        max_kantenwinkel = max(verschneidung.kantenwinkel)
        max_total = max([max_kantenwinkel, max_allowed_angle])

        self.sc2.axes.set_xlim(0, 360)
        self.sc2.axes.set_ylim(0, max_total * 1.2)

        self.sc2.axes.set_xlabel(f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Winkelparameter"]} $\\rightarrow$')
        self.sc2.axes.set_ylabel(f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle2"]} $\\rightarrow$')

        # Improve the appearance of the grid
        self.sc2.axes.grid(True, which='both', linestyle='--', linewidth=0.5)

        # Add a legend with a better placement
        self.sc2.axes.legend(loc='best')

        # Adjust the layout to make room for the labels and title
        plt.tight_layout()

        # Apply the custom formatter to add the degree symbol
        self.sc2.axes.yaxis.set_major_formatter(FuncFormatter(self.degree_formatter))
        self.sc2.axes.xaxis.set_major_formatter(FuncFormatter(self.degree_formatter))

        # Manually set x-axis ticks from 0 to 360 degrees
        self.sc2.axes.set_xticks(range(0, 361, 60))
        self.sc2.axes.set_xticklabels([f'{i}°' for i in range(0, 361, 60)])

        # Create a secondary y-axis for Senkwinkel
        ax2 = self.sc2.axes.twinx()

        # Invert the secondary y-axis
        ax2.set_ylim(180, 180 - max_total * 1.2)
        ax2.set_ylabel(f'$\\leftarrow$ {LANGUAGE_SETTINGS.languagePack["plotErstellung"]["SenkwinkelWerkzeug"]}', color='green')

        # Apply the custom formatter to add the degree symbol
        ax2.yaxis.set_major_formatter(FuncFormatter(self.degree_formatter))

        # Set the color of the right y-axis
        ax2.spines['right'].set_color('green')
        ax2.tick_params(axis='y', colors='green')
        ax2.yaxis.label.set_color('green')

        # Adjust the layout again to make room for the secondary y-axis
        plt.tight_layout()

    def plot_drehwinkel(self) -> None:
        self.sc2.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED
        tool = WERKZEUG_CALCULATED

        numbers_schnittpkt_mitte = []
        # drehwinkel_werkzeug = verschneidung.tcp_translated_phi * 180.0 / math.pi + tool.winkeloffset
        for number in verschneidung.tcp_translated_phi:
            number = (number * 180 / math.pi) + tool.winkeloffset
            numbers_schnittpkt_mitte.append((360.0 - number)%360)

        self.sc2.axes.set_xlabel(
            f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Winkelparameter"]} $\\rightarrow$')
        self.sc2.axes.set_ylabel(f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle1"]} $\\rightarrow$')

        # Use scatter instead of stem
        x_values = verschneidung.omega_deg  # X-values as indices of the list
        y_values = numbers_schnittpkt_mitte  # Y-values as the angles

        self.sc2.axes.scatter(x_values, y_values, c='#009CDA', label=f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle1"]}')

        # Manually set x-axis ticks from 0 to 360 degrees
        self.sc2.axes.set_xlim(0, 360)
        self.sc2.axes.set_xticks(range(0, 361, 60))
        self.sc2.axes.set_xticklabels([f'{i}°' for i in range(0, 361, 60)])

        # y-Axis
        y_min, y_max = self.sc2.axes.get_ylim()
        self.sc2.axes.set_ylim(0, 360)
        self.sc2.axes.set_yticks(range(0, 361, 60))
        self.sc2.axes.set_yticklabels([f'{i}°' for i in range(0, 361, 60)])

        # Optional: Add grid, title, etc.
        self.sc2.axes.grid(True, which='both', linestyle='--', linewidth=0.5)

        # Add a legend with a better placement
        self.sc2.axes.legend(loc='best')

        # Draw the canvas
        self.sc2.draw()

    def plot_patches(self) -> None:
        self.sc.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED

        all_x = []
        all_y = []
        all_z = []

        for i in range(verschneidung.n_points):
            j = (i + 1) % verschneidung.n_points  # ensures j loops back to 0

            X = [verschneidung.x[i], verschneidung.x[i] + verschneidung.kantenvektor_qb_x[i],
                 verschneidung.x[j] + verschneidung.kantenvektor_qb_x[j], verschneidung.x[j]]
            Y = [verschneidung.y[i], verschneidung.y[i] + verschneidung.kantenvektor_qb_y[i],
                 verschneidung.y[j] + verschneidung.kantenvektor_qb_y[j], verschneidung.y[j]]
            Z = [verschneidung.z[i], verschneidung.z[i] + verschneidung.kantenvektor_qb_z[i],
                 verschneidung.z[j] + verschneidung.kantenvektor_qb_z[j], verschneidung.z[j]]
            verts = [list(zip(X, Y, Z))]

            self.sc.axes.add_collection3d(mplot3d.art3d.Poly3DCollection(verts))

            X = [verschneidung.x[i], verschneidung.x[i] + verschneidung.kantenvektor_hb_x[i],
                 verschneidung.x[j] + verschneidung.kantenvektor_hb_x[j], verschneidung.x[j]]
            Y = [verschneidung.y[i], verschneidung.y[i] + verschneidung.kantenvektor_hb_y[i],
                 verschneidung.y[j] + verschneidung.kantenvektor_hb_y[j], verschneidung.y[j]]
            Z = [verschneidung.z[i], verschneidung.z[i] + verschneidung.kantenvektor_hb_z[i],
                 verschneidung.z[j] + verschneidung.kantenvektor_hb_z[j], verschneidung.z[j]]
            verts2 = [list(zip(X, Y, Z))]

            self.sc.axes.add_collection3d(mplot3d.art3d.Poly3DCollection(verts2))

            all_x.extend(X)
            all_y.extend(Y)
            all_z.extend(Z)

        self.sc.axes.set_xlabel('x in mm $\\rightarrow$')
        self.sc.axes.set_ylabel('y in mm $\\rightarrow$')
        self.sc.axes.set_zlabel('z in mm $\\rightarrow$')

        # Calculate limits with 50% padding
        def calculate_limits(data):
            data_min = min(data)
            data_max = max(data)
            padding = 0.5 * (data_max - data_min)
            return data_min - padding- 1, data_max + padding + 1

        x_min, x_max = calculate_limits(all_x)
        y_min, y_max = calculate_limits(all_y)
        z_min, z_max = calculate_limits(all_z)

        self.sc.axes.set_xlim(x_min, x_max)
        self.sc.axes.set_ylim(y_min, y_max)
        self.sc.axes.set_zlim(z_min, z_max)

        self.sc.axes.set_box_aspect(
            [ub - lb for lb, ub in (self.sc.axes.get_xlim(), self.sc.axes.get_ylim(), self.sc.axes.get_zlim())])

    def plot_fase(self) -> None:

        self.sc.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED
        # Plot the main points
        self.sc.axes.scatter(verschneidung.x[1:-1], verschneidung.y[1:-1], verschneidung.z[1:-1], c='#009CDA',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Verschneidungspunkte"])
        # Highlight the start and end points
        self.sc.axes.scatter(verschneidung.schnittpunkt_hb_x, verschneidung.schnittpunkt_hb_y, verschneidung.schnittpunkt_hb_z, c='#99E0F3',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["SchnittpunktHB"])
        self.sc.axes.scatter(verschneidung.schnittpunkt_qb_x, verschneidung.schnittpunkt_qb_y, verschneidung.schnittpunkt_qb_z, c='#232E33',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["SchnittpunktQB"])

        self.sc.axes.quiver(verschneidung.x, verschneidung.y, verschneidung.z, verschneidung.kantenvektor_hb_x,
                            verschneidung.kantenvektor_hb_y, verschneidung.kantenvektor_hb_z,
                            label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Hauptbohrungsvektor"],
                            color="#4E4E4E")
        self.sc.axes.quiver(verschneidung.x, verschneidung.y, verschneidung.z, verschneidung.kantenvektor_qb_x,
                            verschneidung.kantenvektor_qb_y, verschneidung.kantenvektor_qb_z,
                            label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Querbohrungsvektor"],
                            color="#000000")

        self.sc.axes.set_xlabel('x in mm $\\rightarrow$')
        self.sc.axes.set_ylabel('y in mm $\\rightarrow$')
        self.sc.axes.set_zlabel('z in mm $\\rightarrow$')

        self.sc.axes.set_box_aspect(aspect=(1, 1, 1))
        self.sc.axes.set_box_aspect([ub - lb for lb, ub in (getattr(self.sc.axes, f'get_{a}lim')() for a in
                                                            'xyz')])  # notwendig, damit axis gleich skaliert u. Plots nicht verzerrt werden

        # Add a legend
        self.sc.axes.legend(loc='best')

    def plot_TCP_Verschneidung(self) -> None:

        self.sc.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED
        self.sc.axes.scatter(verschneidung.x, verschneidung.y, verschneidung.z, c='#009CDA',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Verschneidungspunkte"])
        self.sc.axes.scatter(verschneidung.tcp_x, verschneidung.tcp_y, verschneidung.tcp_z, c='#4E4E4E',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["TCP"])

        index = 1
        your_mesh = mesh.Mesh.from_file(
            f'STL/Sweep/combined_real_rotated{index:04d}.stl')  # Mesh d. Werkzeugs an Stelle z_min
        vertices = your_mesh.vectors

        self.sc.axes.plot_surface(vertices[:, :, 0], vertices[:, :, 1], vertices[:, :, 2], zorder=0)

        self.sc.axes.set_xlabel('x in mm $\\rightarrow$')
        self.sc.axes.set_ylabel('y in mm $\\rightarrow$')
        self.sc.axes.set_zlabel('z in mm $\\rightarrow$')

        self.sc.axes.set_ylim(min(verschneidung.y), max(verschneidung.y))
        self.sc.axes.set_xlim(min(verschneidung.y), max(verschneidung.x))

        # notwendig, damit axis gleich skaliert u. Plots nicht verzerrt werden
        self.sc.axes.set_box_aspect(aspect=(1, 1, 1))
        self.sc.axes.set_box_aspect([ub - lb for lb, ub in (getattr(self.sc.axes, f'get_{a}lim')() for a in
                                                            'xyz')])

        # Add a legend
        self.sc.axes.legend(loc='best')

    def plot_TCP_Verschneidung_transformed(self) -> None:

        self.sc.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED
        # Plot the main points
        self.sc.axes.scatter(verschneidung.translated_x[1:-1], verschneidung.translated_y[1:-1], verschneidung.translated_z[1:-1], c='#009CDA',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Verschneidungspunkte"])
        # Highlight the start and end points
        self.sc.axes.scatter(verschneidung.translated_x[0], verschneidung.translated_y[0], verschneidung.translated_z[0], c='#99E0F3',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Startpunkt"])
        self.sc.axes.scatter(verschneidung.translated_x[-1], verschneidung.translated_y[-1], verschneidung.translated_z[-1], c='#232E33',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Endpunkt"])

        self.sc.axes.scatter(verschneidung.tcp_translated_x, verschneidung.tcp_translated_y, verschneidung.tcp_translated_z, c='#4E4E4E',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["TCP"])

        self.sc.axes.set_box_aspect(aspect=(1, 1, 1))
        self.sc.axes.set_box_aspect([ub - lb for lb, ub in (getattr(self.sc.axes, f'get_{a}lim')() for a in
                                                            'xyz')])  # notwendig, damit axis gleich skaliert u. Plots nicht verzerrt werden

        self.sc.axes.set_xlabel('x in mm $\\rightarrow$')
        self.sc.axes.set_ylabel('y in mm $\\rightarrow$')
        self.sc.axes.set_zlabel('z in mm $\\rightarrow$')

        # Add a legend
        self.sc.axes.legend(loc='best')

    def plot_werkzeug_combined(self) -> None:

        self.sc.axes.clear()

        your_mesh = mesh.Mesh.from_file('STL/combined_real.stl')
        # self.sc.axes.add_collection3d(mplot3d.art3d.Poly3DCollection(your_mesh.vectors))

        vertices = your_mesh.vectors

        self.sc.axes.plot_surface(vertices[:, :, 0], vertices[:, :, 1], vertices[:, :, 2], edgecolors='k', lw=0.6)

        # Default Zoom:
        self.sc.axes.set_ylim(-8, 8)
        self.sc.axes.set_xlim(-8, 8)
        self.sc.axes.set_zlim(0, 10)

        self.sc.axes.set_xlabel('x in mm $\\rightarrow$')
        self.sc.axes.set_ylabel('y in mm $\\rightarrow$')
        self.sc.axes.set_zlabel('z in mm $\\rightarrow$')

        self.sc.axes.set_box_aspect(aspect=(1, 1, 1))
        self.sc.axes.set_box_aspect([ub - lb for lb, ub in (getattr(self.sc.axes, f'get_{a}lim')() for a in
                                                            'xyz')])  # notwendig, damit axis gleich skaliert u. Plots nicht verzerrt werden

    def plot_verschneidung_mit_werkzeug_an_tiefster_Stelle(self) -> None:
        self.sc.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED
        minimal_z = min(verschneidung.tcp_z)
        minimal_z_index = verschneidung.tcp_z.index(minimal_z)
        print("min tpc_z, Index:", minimal_z, ",", minimal_z_index)
        # Bug bei Bennung der STLs!!!
        your_mesh = mesh.Mesh.from_file(
            f'STL/Sweep/combined_real_rotated{minimal_z_index:04d}.stl')  # Mesh d. Werkzeugs an Stelle z_min
        collection = mplot3d.art3d.Poly3DCollection(your_mesh.vectors, linewidths=1, alpha=0.5)
        face_color = [0, 0, 1]
        collection.set_facecolor(face_color)
        # collection.set_edgecolor(face_color)       wenn edgecolor aktiviert, dann keine Transparenz mehr vorhanden
        self.sc.axes.add_collection3d(collection)

        self.sc.axes.scatter(verschneidung.x, verschneidung.y, verschneidung.z, c='#009CDA',
                             label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Verschneidungspunkte"])

        self.sc.axes.quiver(verschneidung.x, verschneidung.y, verschneidung.z, verschneidung.kantenvektor_hb_x,
                            verschneidung.kantenvektor_hb_y, verschneidung.kantenvektor_hb_z,
                            label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Hauptbohrungsvektor"],
                            color="#4E4E4E")
        self.sc.axes.quiver(verschneidung.x, verschneidung.y, verschneidung.z, verschneidung.kantenvektor_qb_x,
                            verschneidung.kantenvektor_qb_y, verschneidung.kantenvektor_qb_z,
                            label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Querbohrungsvektor"],
                            color="#000000")

        xqb, yqb, zqb = Verschneidung.data_for_cylinder_along_z(0.0, verschneidung.av, verschneidung.d_qb / 2.0,
                                                                -verschneidung.d_qb, verschneidung.d_qb)

        if verschneidung.ebener_Austritt:
            # Plot a flat plane for the second cylinder
            xhb, yhb = np.meshgrid(np.linspace(-verschneidung.d_hb / 2.0, verschneidung.d_hb / 2.0, 30),
                                   np.linspace(-verschneidung.d_hb / 2.0, verschneidung.d_hb / 2.0, 30))
            zhb = np.full_like(xhb, 0.0)
            self.sc.axes.plot_surface(xhb, yhb, zhb, color='grey', alpha=0.3)
        else:
            zhb, yhb, xhb = Verschneidung.data_for_cylinder_along_z(0.0, 0.0, verschneidung.d_hb / 2.0, -30.0, 30.0)
            self.sc.axes.plot_wireframe(xhb, yhb, zhb, color='grey', alpha=0.3)
            # Set cylinder for Querbohrung higher
            zqb += verschneidung.d_hb / 2.0

        self.sc.axes.plot_surface(xqb, yqb, zqb, color='grey', alpha=0.3)

        self.sc.axes.set_xlabel('x in mm $\\rightarrow$')
        self.sc.axes.set_ylabel('y in mm $\\rightarrow$')
        self.sc.axes.set_zlabel('z in mm $\\rightarrow$')

        # Add a legend
        self.sc.axes.legend(loc='best')

        self.sc.axes.view_init(elev=0, azim=0)

        self.sc.axes.set_box_aspect(aspect=(1, 1, 1))
        self.sc.axes.set_box_aspect([ub - lb for lb, ub in (getattr(self.sc.axes, f'get_{a}lim')() for a in 'xyz')])

    def plot_verschneidung_mit_werkzeug(self) -> None:
        self.sc.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED
        minimal_z = min(verschneidung.tcp_z)
        minimal_z_index = verschneidung.tcp_z.index(minimal_z)
        your_mesh = mesh.Mesh.from_file(
            f'STL/Sweep/combined_real_rotated{minimal_z_index:04d}.stl')  # Mesh d. Werkzeugs an Stelle z_min
        collection = mplot3d.art3d.Poly3DCollection(your_mesh.vectors, linewidths=1, alpha=0.5)
        face_color = [0, 0, 1]
        collection.set_facecolor(face_color)
        # collection.set_edgecolor(face_color)       wenn edgecolor aktiviert, dann keine Transparenz mehr vorhanden
        self.sc.axes.add_collection3d(collection)

        self.sc.axes.scatter(verschneidung.x, verschneidung.y, verschneidung.z, facecolor='gray', edgecolor='gray')

        self.sc.axes.quiver(verschneidung.x, verschneidung.y, verschneidung.z, verschneidung.kantenvektor_hb_x,
                            verschneidung.kantenvektor_hb_y, verschneidung.kantenvektor_hb_z, facecolor='gray',
                            edgecolor='gray')
        self.sc.axes.quiver(verschneidung.x, verschneidung.y, verschneidung.z, verschneidung.kantenvektor_qb_x,
                            verschneidung.kantenvektor_qb_y, verschneidung.kantenvektor_qb_z, facecolor='gray',
                            edgecolor='gray')

        self.sc.axes.scatter(verschneidung.x[0], verschneidung.y[0], verschneidung.z[0], facecolor='green')
        self.sc.axes.scatter(verschneidung.x[-1], verschneidung.y[-1], verschneidung.z[-1], facecolor='red')

        xqb, yqb, zqb = Verschneidung.data_for_cylinder_along_z(0.0, verschneidung.av, verschneidung.d_qb / 2.0, -verschneidung.d_qb,
                                                                verschneidung.d_qb)

        if verschneidung.ebener_Austritt:
            # Plot a flat plane for the second cylinder
            xhb, yhb = np.meshgrid(np.linspace(-verschneidung.d_hb / 2.0, verschneidung.d_hb / 2.0, 30),
                                   np.linspace(-verschneidung.d_hb / 2.0, verschneidung.d_hb / 2.0, 30))
            zhb = np.full_like(xhb, 0.0)
            self.sc.axes.plot_surface(xhb, yhb, zhb, color='grey', alpha=0.3)
        else:
            zhb, yhb, xhb = Verschneidung.data_for_cylinder_along_z(0.0, 0.0, verschneidung.d_hb / 2.0, -30.0, 30.0)
            self.sc.axes.plot_surface(xhb, yhb, zhb, color='grey', alpha=0.3)

            # Set cylinder for Querbohrung higher
            zqb += verschneidung.d_hb / 2.0

        self.sc.axes.plot_surface(xqb, yqb, zqb, color='grey', alpha=0.3)

        self.sc.axes.set_xlabel('x in mm $\\rightarrow$')
        self.sc.axes.set_ylabel('y in mm $\\rightarrow$')
        self.sc.axes.set_zlabel('z in mm $\\rightarrow$')

        self.sc.axes.set_box_aspect(aspect=(1, 1, 1))
        self.sc.axes.set_box_aspect([ub - lb for lb, ub in (getattr(self.sc.axes, f'get_{a}lim')() for a in 'xyz')])

    def plot_auslegung_senkwinkel(self) -> None:
        self.sc2.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED

        # Convert position numbers to angles
        angles = [i * (360 / len(verschneidung.kantenwinkel)) for i in range(len(verschneidung.kantenwinkel))]

        # Plot numerically calculated inclination angles
        self.sc2.axes.scatter(
            angles, verschneidung.kantenwinkel, c='C0', marker='o',
            label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle2"]
        )

        # Get the limits of the plot
        x_min, x_max = self.sc2.axes.get_xlim()

        max_allowed_angle = max(verschneidung.kantenwinkel)
        # Plot angle limit line
        self.sc2.axes.axhline(y=max_allowed_angle, color='green', linestyle='--',
                              label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["MaxSenkwinkelWerkzeug"])
        # Fill area below angle limit line (allowed area)
        self.sc2.axes.fill_between([x_min, x_max], max_allowed_angle, 0, color='green', alpha=0.1)

        # Add text label at the axhline
        text = f'Max. Senkwinkel: {math.floor(180 - max_allowed_angle)}\N{DEGREE SIGN}'
        self.sc2.axes.text(x_min + (x_max - x_min) * 0.5, max_allowed_angle * 1.01, text, color='green', va="bottom",
                           ha="center")

        # Set the x-limits and y-limits of the plot to prevent resizing
        max_kantenwinkel = max(verschneidung.kantenwinkel)
        max_total = max([max_kantenwinkel, max_allowed_angle])

        self.sc2.axes.set_xlim(0, 360)
        self.sc2.axes.set_ylim(0, max_total * 1.5)

        self.sc2.axes.set_xlabel(
            f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Winkelparameter"]} $\\rightarrow$')
        self.sc2.axes.set_ylabel(f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle2"]} $\\rightarrow$')

        # Improve the appearance of the grid
        self.sc2.axes.grid(True, which='both', linestyle='--', linewidth=0.5)

        # Add a legend with a better placement
        self.sc2.axes.legend(loc='best')

        # Adjust the layout to make room for the labels and title
        plt.tight_layout()

        # Apply the custom formatter to add the degree symbol
        self.sc2.axes.yaxis.set_major_formatter(FuncFormatter(self.degree_formatter))
        self.sc2.axes.xaxis.set_major_formatter(FuncFormatter(self.degree_formatter))

        # Manually set x-axis ticks from 0 to 360 degrees
        self.sc2.axes.set_xticks(range(0, 361, 60))
        self.sc2.axes.set_xticklabels([f'{i}°' for i in range(0, 361, 60)])

        # Create a secondary y-axis for Senkwinkel
        ax2 = self.sc2.axes.twinx()

        # Invert the secondary y-axis
        ax2.set_ylim(180, 180-(max_total * 1.5))

        # Set ticks for the secondary y-axis using ticks from the first y-axis
        current_y_ticks = self.sc2.axes.get_yticks()
        #ax2.set_yticks([180, max_allowed_angle] + list(current_y_ticks))  # Set ticks for the secondary y-axis
        right_ticks=[180 - num for num in current_y_ticks]
        ax2.set_yticks(right_ticks[0:-1])  # Set ticks for the secondary y-axis

        ax2.set_ylabel(f'$\\leftarrow$ {LANGUAGE_SETTINGS.languagePack["plotErstellung"]["SenkwinkelWerkzeug"]}',
                       color='green')

        # Apply the custom formatter to add the degree symbol
        ax2.yaxis.set_major_formatter(FuncFormatter(self.degree_formatter))

        # Set the color of the right y-axis
        ax2.spines['right'].set_color('green')
        ax2.tick_params(axis='y', colors='green')
        ax2.yaxis.label.set_color('green')

        # Adjust the layout again to make room for the secondary y-axis
        plt.tight_layout()

    def plot_auslegung_freiwinkel(self) -> None:
        self.sc2.axes.clear()

        verschneidung = VERSCHNEIDUNG_CALCULATED

        # Plot numerically calculated inclination angles
        self.sc2.axes.scatter(
            verschneidung.omega_deg, verschneidung.steigungswinkel_num, c='#009CDA', marker='o',
            label="Numerisch"
        )

        # Plot analytically calculated inclination angles
        self.sc2.axes.scatter(
            verschneidung.omega_deg, verschneidung.steigungswinkel_ana, c='#00517F', marker='o',
            label="Analytisch"
        )

        min_freiwinkel = max(verschneidung.steigungswinkel_ana)

        # Plot angle limit line
        self.sc2.axes.axhline(y=min_freiwinkel, color='green', linestyle='--', label="Min. Freiwinkel")

        self.sc2.axes.set_xlabel(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Positionnr"])
        self.sc2.axes.set_ylabel(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle3"])

        # Get the limits of the plot
        x_min, x_max = self.sc2.axes.get_xlim()
        y_min, y_max = self.sc2.axes.get_ylim()

        # Fill area below angle limit line (allowed area)
        self.sc2.axes.fill_between([x_min, x_max], min_freiwinkel, y_min, color='green', alpha=0.1)

        text = f'Min. Freiwinkel: {math.ceil(min_freiwinkel)}\N{DEGREE SIGN}'
        self.sc2.axes.text(x_min + (x_max - x_min) * 0.5, min_freiwinkel * 1.01, text, color='green', va="bottom",
                           ha="center")

        # Set the x-limits and y-limits of the plot to prevent resizing
        max_ana = max(verschneidung.steigungswinkel_ana)
        max_num = max(verschneidung.steigungswinkel_num)
        max_total = max([max_ana, max_num])

        self.sc2.axes.set_xlim(0, 360)
        self.sc2.axes.set_ylim(y_min, max_total * 1.5)

        self.sc2.axes.set_xlabel(
            f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Winkelparameter"]} $\\rightarrow$')
        self.sc2.axes.set_ylabel(f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle3"]} $\\rightarrow$')

        # Apply the custom formatter to add the degree symbol
        self.sc2.axes.yaxis.set_major_formatter(FuncFormatter(self.degree_formatter))
        self.sc2.axes.xaxis.set_major_formatter(FuncFormatter(self.degree_formatter))

        # Manually set x-axis ticks from 0 to 360 degrees
        self.sc2.axes.set_xticks(range(0, 361, 60))
        self.sc2.axes.set_xticklabels([f'{i}°' for i in range(0, 361, 60)])

        # Improve the appearance of the grid
        self.sc2.axes.grid(True, which='both', linestyle='--', linewidth=0.5)

        # Create a secondary y-axis for Freiwinkel
        ax2 = self.sc2.axes.twinx()

        # Set the same y-limits as the primary y-axis
        ax2.set_ylim(self.sc2.axes.get_ylim())
        ax2.set_ylabel(f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ParamAngle4"]} $\\rightarrow$',
                       color='green')

        # Apply the custom formatter to add the degree symbol
        ax2.yaxis.set_major_formatter(FuncFormatter(self.degree_formatter))

        # Set the color of the right y-axis
        ax2.spines['right'].set_color('green')
        ax2.tick_params(axis='y', colors='green')
        ax2.yaxis.label.set_color('green')

        # Add a legend with a better placement
        self.sc2.axes.legend(loc='best')

        # Adjust the layout to make room for the labels and title
        plt.tight_layout()

    def plot_auslegung_tz(self) -> None:
        verschneidung = VERSCHNEIDUNG_CALCULATED
        if not verschneidung.Auslegung:
            tool = WERKZEUG_CALCULATED
        text_color = 'black'
        text_size = 10
        npixel_x = 469
        npixel_y = 182

        # Calculate the limits
        max_senkwinkel = 180.0 - max(verschneidung.kantenwinkel)
        min_freiwinkel = max(verschneidung.steigungswinkel_ana)
        if verschneidung.Auslegung:
            max_d_hals = verschneidung.d_qb - 2 * verschneidung.fb_soll
            senkwinkel = 90
        else:
            max_d_hals = tool.d_kopf - 2 * math.sin(tool.schneidenwinkel/180*math.pi) * verschneidung.fb_soll
            senkwinkel = WERKZEUG_CALCULATED.schneidenwinkel
        x_rechts = verschneidung.av + 0.5 * verschneidung.d_qb + verschneidung.fb_soll

        if x_rechts < (verschneidung.d_hb / 2):
            max_kopflaenge = 2*np.sqrt((verschneidung.d_hb / 2) ** 2 - x_rechts ** 2)
        else:
            max_kopflaenge = 0

        # Halslänge
        if not verschneidung.ebener_Austritt:
            fb_x = verschneidung.fb_soll * np.sin(senkwinkel / 180 * np.pi)
            if verschneidung.d_hb / 2.0 < verschneidung.d_qb / 2.0 + verschneidung.av + fb_x:
                halslaenge = 1.5 * verschneidung.d_qb + verschneidung.bohrtiefe
            else:
                schnittpunkt_hb_qb = -1* verschneidung.bohrtiefe + np.sqrt((verschneidung.d_hb / 2.0) ** 2 - (
                        verschneidung.d_qb / 2.0 + verschneidung.av + fb_x) ** 2)
                halslaenge = 1.5 * verschneidung.d_qb - schnittpunkt_hb_qb
        else:
            halslaenge = 1.5 * verschneidung.d_qb + verschneidung.bohrtiefe

        self.sc2.axes.clear()
        # Bild laden
        img = image.imread('./Images/tz_werkzeug_auslegung_unbeschriftet.png')

        # Bild anzeigen
        self.sc2.axes.imshow(img)

        # Freiwinkel
        self.sc2.axes.text(-75 / npixel_x, (npixel_y - 135) / npixel_y,
                           f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Freiwinkel"]} > {math.ceil(min_freiwinkel)}\N{DEGREE SIGN}',
                           horizontalalignment='left',
                           verticalalignment='center',
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Senkwinkel
        self.sc2.axes.text(99 / npixel_x, (npixel_y - 25) / npixel_y,
                           f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Senkwinkel"]} < {math.floor(max_senkwinkel)}\N{DEGREE SIGN}',
                           horizontalalignment='left',
                           verticalalignment='bottom',
                           rotation=55,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Durchmesser Kopf
        self.sc2.axes.text(-2 / npixel_x, (npixel_y - 23) / npixel_y,
                           f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Kopfdurchmesser"]}=\u2300{round(verschneidung.d_qb, 3)} mm',
                           horizontalalignment='right',
                           verticalalignment='bottom',
                           rotation=90,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Durchmesser Schaft
        self.sc2.axes.text(280 / npixel_x, (npixel_y -33) / npixel_y,
                           f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Halsdurchmesser"]}<\u2300{math.floor(max_d_hals*10)/10} mm',
                           horizontalalignment='right',
                           verticalalignment='bottom',
                           rotation=90,
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Spannutlaenge
        self.sc2.axes.text(213.5 / npixel_x, (npixel_y - 185) / npixel_y,
                           f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Halslaenge"]} > {math.ceil(halslaenge*10)/10} mm',
                           horizontalalignment='center',
                           verticalalignment='top',
                           transform=self.sc2.axes.transAxes,
                           fontweight='bold',
                           color=text_color,
                           fontsize=text_size)

        # Laenge Kopf
        if not verschneidung.ebener_Austritt:
            self.sc2.axes.text(106 / npixel_x, (npixel_y - 137) / npixel_y,
                               f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["KopflaengeGesamt"]}\n< {math.floor(max_kopflaenge*10)/10} mm',
                               horizontalalignment='center',
                               verticalalignment='top',
                               transform=self.sc2.axes.transAxes,
                               fontweight='bold',
                               color=text_color,
                               fontsize=text_size)
        else:
            self.sc2.axes.text(106 / npixel_x, (npixel_y - 137) / npixel_y,
                               LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Freiraum"],
                               horizontalalignment='center',
                               verticalalignment='top',
                               transform=self.sc2.axes.transAxes,
                               fontweight='bold',
                               color=text_color,
                               fontsize=text_size)

        # Achsen deaktivieren
        self.sc2.axes.axis('off')
        self.sc2.axes.set_aspect('equal')

    def plot_auslegung_kopflaenge(self) -> None:
        verschneidung = VERSCHNEIDUNG_CALCULATED
        if verschneidung.ebener_Austritt == True:
            self.plot_auslegung_kopflaenge_eben()
            return

        av = verschneidung.av
        d_qb = verschneidung.d_qb
        fb = verschneidung.fb_soll
        d_hb = verschneidung.d_hb

        self.sc2.axes.clear()

        # Calculate Intersection points
        x_rechts = av + 0.5 * d_qb + fb
        if x_rechts < (d_hb / 2):
            y_rechts = np.sqrt((d_hb / 2) ** 2 - x_rechts ** 2)
        else:
            y_rechts = 0

        # Thin vertical lines
        self.sc2.axes.plot([0, 0], [0, 1.3 * d_hb], color='black', linewidth=0.5)
        self.sc2.axes.plot([av, av], [0, 1.3 * d_hb], color='black', linewidth=0.5, linestyle='-.')
        self.sc2.axes.plot([av + 0.5 * d_qb, av + 0.5 * d_qb], [0, 1.3 * d_hb], color='black', linewidth=0.5)
        self.sc2.axes.plot([av + 0.5 * d_qb + fb, av + 0.5 * d_qb + fb], [0, 1.3 * d_hb], color='black', linewidth=0.5)
        self.sc2.axes.plot([x_rechts, x_rechts], [y_rechts, -y_rechts], color='#009CDA', linewidth=1)

        # Horizontal Lines
        self.sc2.axes.plot([x_rechts, 1.3 * d_hb], [y_rechts, y_rechts], color='black', linewidth=0.5)
        self.sc2.axes.plot([x_rechts, 1.3 * d_hb], [-y_rechts, -y_rechts], color='black', linewidth=0.5)

        # Arrow Höhe Kopf
        arrow_color = 'black'  # Color of the arrow
        arrow_width = 0.02  # Width of the arrow
        arrow_lenght = 2
        head_w = 0.5
        self.sc2.axes.annotate(
            '', xy=(1.25 * d_hb, y_rechts), xytext=(1.25 * d_hb, y_rechts-(2*y_rechts)),
            arrowprops=dict(facecolor='#009CDA', edgecolor='#009CDA', arrowstyle='<|-|>')
        )
        #self.sc2.axes.arrow(1.25 * d_hb, y_rechts, 0, -(2*y_rechts) + 2, color=arrow_color, width=arrow_width,
        #                    head_length=arrow_lenght, head_width=head_w)
        #self.sc2.axes.arrow(1.25 * d_hb, -y_rechts, 0, 2*y_rechts - 2, color=arrow_color, width=arrow_width,
        #                    head_length=arrow_lenght, head_width=head_w)
        self.sc2.axes.text(1.27 * d_hb, 0, f'{round(2*y_rechts, 3)} mm', ha='left', va='center', rotation=90, color='#009CDA')

        self.sc2.axes.text(-(d_qb/2), 1.3 * d_hb, f'{round(av, 3)} mm', ha='left', va='bottom', color='#99E0F3')
        self.sc2.axes.text(av-(d_qb / 2), 1.2 * d_hb, f'{round(d_qb/2, 3)} mm', ha='right', va='center', color='#232E33')
        self.sc2.axes.text(av + 1 * d_qb + fb, 1.15 * d_hb, f'{round(fb, 3)} mm', ha='left', va='center',
                           color='#4E4E4E')

        #'#009CDA' '#99E0F3' '#232E33''#232E33'

        # Draw Arrow
        self.sc2.axes.annotate(
            '', xy=(0, 1.25 * d_hb), xytext=(-(d_qb/2), 1.25 * d_hb),
            arrowprops=dict(facecolor='#99E0F3', edgecolor='#99E0F3', arrowstyle='-|>')
        )
        self.sc2.axes.annotate(
            '', xy=(av, 1.25 * d_hb), xytext=(av+(d_qb / 2), 1.25 * d_hb),
            arrowprops=dict(facecolor='#99E0F3', edgecolor='#99E0F3', arrowstyle='-|>')
        )

        self.sc2.axes.annotate(
            '', xy=(av, 1.20 * d_hb), xytext=(av - (d_qb / 2), 1.20 * d_hb),
            arrowprops=dict(facecolor='#232E33', edgecolor='#232E33', arrowstyle='-|>')
        )
        self.sc2.axes.annotate(
            '', xy=(av + (d_qb / 2), 1.20 * d_hb), xytext=(av + d_qb, 1.20 * d_hb),
            arrowprops=dict(facecolor='#232E33', edgecolor='#232E33', arrowstyle='-|>')
        )

        self.sc2.axes.annotate(
            '', xy=(av + 0.5 * d_qb, 1.15 * d_hb), xytext=(av + fb, 1.15 * d_hb),
            arrowprops=dict(facecolor='#232E33', edgecolor='#4E4E4E', arrowstyle='-|>')
        )

        self.sc2.axes.annotate(
            '', xy=(av + 0.5 * d_qb + fb, 1.15 * d_hb), xytext=(av + 1 * d_qb + fb, 1.15 * d_hb),
            arrowprops=dict(facecolor='#232E33', edgecolor='#4E4E4E', arrowstyle='-|>')
        )

        # Horizontal lines to connect arrows
        self.sc2.axes.plot([0, av], [1.25 * d_hb, 1.25 * d_hb], color='#99E0F3', linewidth=0.5, label='av')
        self.sc2.axes.plot([av, av + (d_qb / 2)], [1.20 * d_hb, 1.20 * d_hb], color='#232E33', linewidth=0.5, label='$r_{qb}$')
        self.sc2.axes.plot([av + (d_qb / 2), av + (d_qb / 2) + fb], [1.15 * d_hb, 1.15 * d_hb], color='#4E4E4E', linewidth=0.5,
                           label='FB')
        #self.sc2.axes.text(-(d_qb/2), 1.27 * d_hb, 'av', ha='left', va='bottom')
        #self.sc2.axes.text(av + d_qb, 1.22 * d_hb, '$r_{qb}$', ha='right', va='bottom')

        # Square
        #self.sc2.axes.plot([-d_qb, d_qb], [d_qb, d_qb])
        shaded_square = Rectangle((-d_hb, -d_hb), 2*d_hb, 2*d_hb, hatch='/', fill=False, linewidth=0)
        self.sc2.axes.add_patch(shaded_square)
        self.sc2.axes.plot([-(1 * d_hb), 1 * d_hb], [1*d_hb, 1*d_hb], color='#000000')

        # Rectancle
        qb_rectangle = Rectangle((-d_qb/2 + av, 0), d_qb, d_hb,  facecolor='white', edgecolor='black')
        self.sc2.axes.add_patch(qb_rectangle)

        # Circle at center
        circle = Circle((0, 0), radius=d_hb / 2, facecolor='white', edgecolor='black')
        self.sc2.axes.add_patch(circle)

        self.sc2.axes.axis('off')
        self.sc2.axes.set_aspect('equal')
        self.sc2.axes.set_xlim(-(1.5*d_hb), 1.5*d_hb)
        self.sc2.axes.set_ylim(-(1.5*d_hb), 1.5*d_hb)

        # Add a legend with a better placement
        self.sc2.axes.legend(loc='best')

        # Adjust the layout to make room for the labels and title
        plt.tight_layout()

    def plot_auslegung_kopflaenge_eben(self):
        verschneidung = VERSCHNEIDUNG_CALCULATED
        d_qb = verschneidung.d_qb
        bohrtiefe = -1 * verschneidung.bohrtiefe

        # Upper plate
        self.sc2.axes.fill_between(x=(-(2 * d_qb), 2 * d_qb), y1=0, y2=bohrtiefe, color='none', hatch='/', edgecolor='black', linewidth=0)
        self.sc2.axes.plot([-(2 * d_qb), 2 * d_qb], [0, 0], color='#000000')
        self.sc2.axes.plot([-(2 * d_qb), 2 * d_qb], [bohrtiefe, bohrtiefe], color='#000000')

        # Rectancle QB
        qb_rectangle = Rectangle((-d_qb / 2, 0), d_qb, bohrtiefe, facecolor='white', edgecolor='black')
        self.sc2.axes.add_patch(qb_rectangle)
        self.sc2.axes.plot([0, 0], [0.5 * d_qb, bohrtiefe - 0.5 * d_qb], color='black', linewidth=0.5, linestyle='-.')

        # Lower plate
        self.sc2.axes.fill_between(x=(-(2 * d_qb), 2 * d_qb), y1=(bohrtiefe - 2 * d_qb), y2=(bohrtiefe - 2.5 * d_qb), color='none', hatch='/', edgecolor='black', linewidth=0)
        self.sc2.axes.plot([-(2 * d_qb), 2 * d_qb], [(bohrtiefe - 2 * d_qb), (bohrtiefe - 2 * d_qb)], color='#000000')

        # Horizontal lines
        self.sc2.axes.plot([-(2 * d_qb), 2.5 * d_qb], [0, 0], color='#000000', linewidth=0.5)
        self.sc2.axes.plot([-(2 * d_qb), 2.5 * d_qb], [bohrtiefe, bohrtiefe], color='#000000', linewidth=0.5)
        self.sc2.axes.plot([-(2 * d_qb), 2.5 * d_qb], [(bohrtiefe - 2 * d_qb), (bohrtiefe - 2 * d_qb)], color='#000000', linewidth=0.5)

        # '#009CDA' '#99E0F3' '#232E33''#232E33'
        # Draw Arrow
        self.sc2.axes.annotate(
            '', xy=(2.4 * d_qb, bohrtiefe), xytext=(2.4 * d_qb, 0),
            arrowprops=dict(facecolor='#232E33', edgecolor='#232E33', arrowstyle='<|-|>')
        )

        self.sc2.axes.annotate(
            '', xy=(2.4 * d_qb, bohrtiefe), xytext=(2.4 * d_qb, bohrtiefe - 2 * d_qb),
            arrowprops=dict(facecolor='#009CDA', edgecolor='#009CDA', arrowstyle='<|-|>')
        )

        self.sc2.axes.text(2.5 * d_qb, 0.5 * bohrtiefe, LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Bohrtiefe"],
                           ha='left', va='center', rotation=90, color='#000000')

        self.sc2.axes.text(2.5 * d_qb, bohrtiefe - d_qb, LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Freiraum"],
                           ha='left', va='center', rotation=90, color='#009CDA')

        self.sc2.axes.axis('off')
        self.sc2.axes.set_aspect('equal')

    def plot_auslegung_halslaenge(self) -> None:
        verschneidung = VERSCHNEIDUNG_CALCULATED
        if verschneidung.ebener_Austritt == True:
            self.plot_auslegung_halslaenge_eben()
            return
        av = verschneidung.av
        d_qb = verschneidung.d_qb
        fb = verschneidung.fb_soll
        bohrtiefe = -1 * verschneidung.bohrtiefe
        d_hb = verschneidung.d_hb
        if verschneidung.Auslegung == True:
            senkwinkel = 90
        else:
            senkwinkel = WERKZEUG_CALCULATED.schneidenwinkel
        fb_x = fb * np.sin(senkwinkel / 180 * np.pi)

        self.sc2.axes.clear()

        # Calculate halslaenge
        halslaenge = verschneidung.bohrtiefe - d_hb / 2.0 + np.sqrt((d_hb / 2.0) ** 2 - (
                d_qb / 2.0 + av) ** 2) + fb_x

        if (d_qb / 2.0 + av + fb_x) < (d_hb / 2.0):
            schnittpunkt_hb_qb = bohrtiefe + np.sqrt((d_hb / 2.0) ** 2 - (
                    d_qb / 2.0 + av + fb_x) ** 2)
        else:
            schnittpunkt_hb_qb = bohrtiefe

        self.sc2.axes.set_xlim(-(2 * d_hb), 2.5 * d_hb)
        self.sc2.axes.set_ylim(bohrtiefe - (1 * d_hb), 1.5 * d_hb)

        # Shade area between lower y limit and y=0 with diagonal lines
        y_lower_limit = bohrtiefe - (0.75 * d_hb)
        y_upper_limit = 0

        self.sc2.axes.fill_between(x=(-(1 * d_hb), 1 * d_hb), y1=y_lower_limit, y2=y_upper_limit, color='none',
                                   hatch='/',
                                   edgecolor='black', linewidth=0)
        self.sc2.axes.plot([-(1 * d_hb), (1 * d_hb)], [0, 0], color='#000000')

        # Rectangle for qb
        qb_rectangle = Rectangle((-d_qb / 2 + av, 0), d_qb, bohrtiefe, facecolor='white', edgecolor='black')
        self.sc2.axes.add_patch(qb_rectangle)

        # Circle for HB
        circle = Circle((0, bohrtiefe), radius=d_hb / 2, facecolor='white', edgecolor='black')
        self.sc2.axes.add_patch(circle)

        # Vertical lines
        self.sc2.axes.plot([av, av], [0.75 * d_qb, bohrtiefe], color='black', linewidth=0.5, linestyle='-.')

        # Horizontal Lines
        self.sc2.axes.plot([-(1.45 * d_hb), 1.35 * d_hb], [1.5 * d_qb, 1.5 * d_qb], color='black', linewidth=0.5)
        self.sc2.axes.plot([-(1.45 * d_hb), 0], [0, 0], color='black', linewidth=0.5)
        self.sc2.axes.plot([-(1.45 * d_hb), 0], [bohrtiefe, bohrtiefe], color='black', linewidth=0.5)
        self.sc2.axes.plot([-(1.35 * d_hb), 1.35 * d_hb], [schnittpunkt_hb_qb, schnittpunkt_hb_qb], color='black',
                           linewidth=0.5)

        # Labels for legend
        self.sc2.axes.plot([], [], color='#009CDA',
                           label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["minHalslaenge"])
        self.sc2.axes.plot([], [], color='#99E0F3', label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Bohrtiefe"])
        self.sc2.axes.plot([], [], color='#232E33',
                           label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Schnittpunkt_HB_QB"])
        self.sc2.axes.plot([], [], color='#4E4E4E', label='$1.5 \\cdot d_{qb}$')

        # Draw Arrow
        self.sc2.axes.annotate(
            '', xy=(-(1.4 * d_hb), bohrtiefe), xytext=(-(1.4 * d_hb), 0),
            arrowprops=dict(facecolor='#99E0F3', edgecolor='#99E0F3', arrowstyle='<|-|>')
        )

        self.sc2.axes.annotate(
            '', xy=(-(1.3 * d_hb), bohrtiefe), xytext=(-(1.3 * d_hb), schnittpunkt_hb_qb),
            arrowprops=dict(facecolor='#232E33', edgecolor='#232E33', arrowstyle='<|-|>')
        )

        self.sc2.axes.annotate(
            '', xy=(-(1.4 * d_hb), 0), xytext=(-(1.4 * d_hb), 1.5 * d_qb),
            arrowprops=dict(facecolor='#4E4E4E', edgecolor='#4E4E4E', arrowstyle='<|-|>')
        )

        self.sc2.axes.annotate(
            '', xy=((1.3 * d_hb), schnittpunkt_hb_qb), xytext=((1.3 * d_hb), 1.5 * d_qb),
            arrowprops=dict(facecolor='#009CDA', edgecolor='#009CDA', arrowstyle='<|-|>')
        )

        # Text at bortiefe
        self.sc2.axes.text(-(1.45 * d_hb), 0.5 * bohrtiefe, f'{round(abs(bohrtiefe), 3)} mm', ha='right', va='center',
                           rotation=90, color='#99E0F3')

        # Text at schnittpunkt
        val = 0.5 * (schnittpunkt_hb_qb + bohrtiefe)
        self.sc2.axes.text(-(1.25 * d_hb), val, f'{round(abs((bohrtiefe-schnittpunkt_hb_qb)), 3)} mm', ha='left', va='center',
                           rotation=90, color='#232E33')

        # Text at 1.5 d_qb
        self.sc2.axes.text(-(1.45 * d_hb), 0.75*d_qb, f'{round(1.5 * d_qb, 3)} mm', ha='right', va='center',
                           rotation=90, color='#4E4E4E')

        # Text at right arrow
        val = 1.5 * d_qb - schnittpunkt_hb_qb
        self.sc2.axes.text(1.35 * d_hb, schnittpunkt_hb_qb + 0.5 * val, f'{round(val, 3)} mm', ha='left', va='center',
                           rotation=90, color='#009CDA')


        self.sc2.axes.set_aspect('equal')
        self.sc2.axes.axis('off')

        # Add a legend with a better placement
        self.sc2.axes.legend(loc='upper right', bbox_to_anchor=(1, 1), borderaxespad=0.)

        # Adjust the layout to make room for the labels and title
        plt.tight_layout()

    def plot_auslegung_halslaenge_eben(self):
        verschneidung = VERSCHNEIDUNG_CALCULATED
        d_qb = verschneidung.d_qb
        bohrtiefe = -1 * verschneidung.bohrtiefe

        # Upper plate
        self.sc2.axes.fill_between(x=(-(2 * d_qb), 2 * d_qb), y1=0, y2=bohrtiefe, color='none', hatch='/', edgecolor='black', linewidth=0)
        self.sc2.axes.plot([-(2 * d_qb), 2 * d_qb], [0, 0], color='#000000')
        self.sc2.axes.plot([-(2 * d_qb), 2 * d_qb], [bohrtiefe, bohrtiefe], color='#000000')

        # Rectancle QB
        qb_rectangle = Rectangle((-d_qb / 2, 0), d_qb, bohrtiefe, facecolor='white', edgecolor='black')
        self.sc2.axes.add_patch(qb_rectangle)
        self.sc2.axes.plot([0, 0], [0.5 * d_qb, bohrtiefe - 0.5 * d_qb], color='black', linewidth=0.5, linestyle='-.')

        # Lower plate
        self.sc2.axes.fill_between(x=(-(2 * d_qb), 2 * d_qb), y1=(bohrtiefe - 2 * d_qb), y2=(bohrtiefe - 2.5 * d_qb), color='none', hatch='/', edgecolor='black', linewidth=0)
        self.sc2.axes.plot([-(2 * d_qb), 2 * d_qb], [(bohrtiefe - 2 * d_qb), (bohrtiefe - 2 * d_qb)], color='#000000')

        # Horizontal lines
        self.sc2.axes.plot([-(2.5 * d_qb), 2.0 * d_qb], [0, 0], color='#000000', linewidth=0.5)
        self.sc2.axes.plot([-(2.5 * d_qb), 2.5 * d_qb], [bohrtiefe, bohrtiefe], color='#000000', linewidth=0.5)
        self.sc2.axes.plot([-(2.5 * d_qb), 2.5 * d_qb], [1.5 * d_qb, 1.5 * d_qb], color='#000000', linewidth=0.5)

        # '#009CDA' '#99E0F3' '#232E33''#232E33'
        # Draw Arrow
        self.sc2.axes.annotate(
            '', xy=(-2.4 * d_qb, bohrtiefe), xytext=(-2.4 * d_qb, 0),
            arrowprops=dict(facecolor='#99E0F3', edgecolor='#99E0F3', arrowstyle='<|-|>')
        )

        self.sc2.axes.annotate(
            '', xy=(-2.4 * d_qb, 0), xytext=(-2.4 * d_qb, 1.5 * d_qb),
            arrowprops=dict(facecolor='#4E4E4E', edgecolor='#4E4E4E', arrowstyle='<|-|>')
        )

        self.sc2.axes.annotate(
            '', xy=(2.4 * d_qb, bohrtiefe), xytext=(2.4 * d_qb, 1.5 * d_qb),
            arrowprops=dict(facecolor='#009CDA', edgecolor='#009CDA', arrowstyle='<|-|>')
        )

        val = 1.5 * d_qb - bohrtiefe
        self.sc2.axes.text(2.5 * d_qb, bohrtiefe + 0.5 * val, f'{round(val, 3)} mm', ha='left', va='center',
                           rotation=90, color='#009CDA')

        #self.sc2.axes.text(2.5 * d_qb, 0.5 * bohrtiefe, LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Bohrtiefe"],
        #                   ha='left', va='center', rotation=90, color='#000000')

        #self.sc2.axes.text(2.5 * d_qb, bohrtiefe - d_qb, LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Freiraum"],
        #                   ha='left', va='center', rotation=90, color='#009CDA')

        # Labels for legend
        self.sc2.axes.plot([], [], color='#009CDA', label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["minHalslaenge"])
        self.sc2.axes.plot([], [], color='#99E0F3', label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Bohrtiefe"])
        self.sc2.axes.plot([], [], color='#4E4E4E', label='$1.5 \\cdot d_{qb}$')

        self.sc2.axes.axis('off')
        self.sc2.axes.set_aspect('equal')

        # Add a legend with a better placement
        self.sc2.axes.legend(loc='best')

        # Improve the appearance of the grid
        # self.sc2.axes.grid(True, which='both', linestyle='--', linewidth=0.5)

        # Adjust the layout to make room for the labels and title
        plt.tight_layout()

    def plot_auslegung_halsdurchmesser(self):
        verschneidung = VERSCHNEIDUNG_CALCULATED

        # Extract values from verschneidung
        d_qb = verschneidung.d_qb
        fb_soll = verschneidung.fb_soll

        # Generate x values from 0 to 90 degrees
        x_degrees = np.linspace(0, 90, 500)
        x_radians = np.deg2rad(x_degrees)

        # Calculate D_hals
        d_hals = d_qb - 2 * (fb_soll * np.sin(x_radians))

        max_allowed_angle = max(verschneidung.kantenwinkel)
        max_senkwinkel = 180 - max_allowed_angle
        max_d = d_qb - 2 * (fb_soll * np.sin(np.deg2rad(max_senkwinkel)))

        self.sc2.axes.plot(x_degrees, d_hals, color='#009CDA', label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["MaxHalsdurchmesser"])
        # Draw a vertical green dashed line at max_senkwinkel

        [ymin, ymax] = self.sc2.axes.get_ylim()

        self.sc2.axes.plot([max_senkwinkel, max_senkwinkel], [ymin, max_d], color='green', linestyle='--', label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["MaxSenkwinkelWerkzeug"])

        # Shade area under the curve up to max_senkwinkel
        self.sc2.axes.fill_between(x_degrees, d_hals, where=(x_degrees <= max_senkwinkel), color='green', alpha=0.1)

        if not verschneidung.Auslegung:
            tool_senkwinkel = verschneidung.werkzeug.schneidenwinkel
            tool_d = d_qb - 2 * (fb_soll * np.sin(np.deg2rad(tool_senkwinkel)))
            self.sc2.axes.plot([tool_senkwinkel, tool_senkwinkel], [ymin, tool_d], color='#4E4E4E', linestyle='--',
                               label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["SenkwinkelWerkzeug"])
            self.sc2.axes.plot([0, tool_senkwinkel], [tool_d, tool_d], color='#00517F', linestyle='--',
                               label=LANGUAGE_SETTINGS.languagePack["plotErstellung"]["MaxHalsdurchmesserWerkzeug"])

            # Add text label at the axhline
            text = f'{round(tool_d, 2)} mm'
            self.sc2.axes.text(tool_senkwinkel * 0.5, tool_d, text, va="bottom", ha="center", color='#00517F')


        # Set x-Limits
        self.sc2.axes.set_xlim(0, 90)
        self.sc2.axes.set_ylim(ymin, ymax)

        # Improve the appearance of the grid
        self.sc2.axes.grid(True, which='both', linestyle='--', linewidth=0.5)

        self.sc2.axes.set_xlabel(
            f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["Senkwinkel"]} $\\rightarrow$')
        self.sc2.axes.set_ylabel(f'{LANGUAGE_SETTINGS.languagePack["plotErstellung"]["MaxHalsdurchmesser"]} [mm] $\\rightarrow$')
        self.sc2.axes.xaxis.set_major_formatter(FuncFormatter(self.degree_formatter))

        # Add a legend with a better placement
        self.sc2.axes.legend(loc='best')

        # Adjust the layout to make room for the labels and title
        plt.tight_layout()


#class representing the extended window for a plot
class WindowPlot(QWidget):
    """
        Ausgegliedertes Fenster für Plots
    """
    def __init__(self, PartenWidget: QWidget):
        """Create a seperate Window for the plot"""
        super().__init__()
        self.ParentWidget = PartenWidget
        currentIndex= self.ParentWidget.tabsPlot.currentIndex()
        currentWidget= self.ParentWidget.tabsPlot.currentWidget()

        self.layout=currentWidget.layout
        #define the button to move plot back to a tab
        self.buttonIncl = QPushButton("")
        self.buttonIncl.clicked.connect(self.InclWindowToTab)
        self.buttonIncl.setIcon(QIcon('Images/ToWindow.png'))
        self.buttonIncl.setToolTip(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ToolTipButtonInclude"])

        currentWidget.layoutH.replaceWidget(currentWidget.buttonExtend, self.buttonIncl)
        self.layoutH =currentWidget.layoutH
        self.setLayout(self.layout)
        self.setWindowTitle(currentWidget.name)
        self.ParentWidget.tabsPlot.removeTab(currentIndex)

    def InclWindowToTab(self):
        """function that creates a tab out of this extended window and includes it in the main window"""
        tempTab = QWidget()
        tempTab.name = self.windowTitle()

        #redefine extend button
        tempTab.buttonExtend = QPushButton("")
        tempTab.buttonExtend.clicked.connect(self.ParentWidget.ExtentTabToNewWindow)
        tempTab.buttonExtend.setIcon(QIcon('Images/ToWindow.png'))
        tempTab.buttonExtend.setToolTip(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["ToolTipButtonExtend"])

        tempTab.layout=self.layout
        self.layoutH.replaceWidget(self.buttonIncl , tempTab.buttonExtend)
        tempTab.layoutH=self.layoutH
        tempTab.setLayout(tempTab.layout)

        self.ParentWidget.tabsPlot.addTab(tempTab,tempTab.name)#
        self.close()

#represents the window for selecting and deselcting plots
class EinstellungPlotsWindow(QWidget):
    """
    Einstellungsfenster für die Plots
    """
    def __init__(self,PartenWidget: QWidget) -> None:
        """Create the Settings Window to select the plots"""
        super().__init__()
        layout = QVBoxLayout()
        self.ParentWidget=PartenWidget

        label=QLabel(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["LabelEinstellungsWindow"])
        layout.addWidget(label)
        self.setWindowTitle(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["buttonPlotSetting"])

        #checkbox Liste
        self.listCheckboxes = QListWidget()
        global LIST_PLOT_NAMES,LIST_WANTED_PLOTS
        for name in LIST_PLOT_NAMES:
            item= QListWidgetItem(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["listPlotNames"][name])
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            if name in LIST_WANTED_PLOTS:
                item.setCheckState(Qt.Checked)
            else:
                item.setCheckState(Qt.Unchecked)
            self.listCheckboxes.addItem(item)
        layout.addWidget(self.listCheckboxes)

        #buttons
        layoutButtons= QHBoxLayout()
        self.buttonSelect=QPushButton(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["buttonSelect"])
        self.buttonSelect.clicked.connect(self.selectAll)
        buttonSpeichern = QPushButton(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["buttonSpeichern"])
        buttonSpeichern.clicked.connect(self.saveSettingsPlot)
        layoutButtons.addWidget(self.buttonSelect)
        layoutButtons.addWidget(buttonSpeichern)
        layout.addLayout(layoutButtons)

        self.setLayout(layout)

    def selectAll(self):
        """select all checkboxes"""
        for i in range(0, self.listCheckboxes.count()):
            item=self.listCheckboxes.item(i)
            item.setCheckState(Qt.Checked)
        self.buttonSelect.clicked.connect(self.deselectAll)

    def deselectAll(self):
        """deselects all checkboxes"""
        for i in range(0, self.listCheckboxes.count()):
            item=self.listCheckboxes.item(i)
            item.setCheckState(Qt.Unchecked)
        self.buttonSelect.clicked.connect(self.selectAll)

    def saveSettingsPlot(self):
        """save the selection of checkboxes"""
        global LIST_WANTED_PLOTS
        LIST_WANTED_PLOTS=[]
        for i in range(0, self.listCheckboxes.count()):
            item = self.listCheckboxes.item(i)
            if item.checkState()==Qt.Checked:
                LIST_WANTED_PLOTS.append(LIST_PLOT_NAMES[i])

        self.ParentWidget.setConnectionsPlotErstellungsButton()
        GUI_SETTINGS["DefaultPlots"]=LIST_WANTED_PLOTS
        utils.globalSettings.writeSettings()
        self.ParentWidget.mainWindow.showStatusbarmessage(LANGUAGE_SETTINGS.languagePack["plotErstellung"]["StatusBarSettingsSaved"],time=5000)
        self.close()

