/*
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                                                 ┃
┃         Class Name(s): SmithBasics, GraphicsScene                                               ┃
┃             File Name: smithbasics.cpp                                                          ┃
┃                Author: Michael Krämer                                                           ┃
┃                 Email: Michael@dk8pp.de                                                         ┃
┃                  Date: 2024-2026                                                                ┃
┃                  Tool: Qt                                                                       ┃
┃                Device: Windows/Linux                                                            ┃
┃               Version: 0.1                                                                      ┃
┃        Program status: still testing                                                            ┃
┃                                                                                                 ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃                                                                                                 ┃
┃  Purpose: Basic functions to generate and modify a Smith Chart                                  ┃
┃                                                                                                 ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃                                                                                                 ┃
┃  © Copyright 2024-2026 Michael Krämer, DK8PP                                                    ┃
┃                                                                                                 ┃
┃  This program is free software: you can redistribute it and/or modify it under the terms of     ┃
┃  the GNU Lesser General Public License as published by the Free Software Foundation, either     ┃
┃  version 3 of the License, or (at your option) any later version.                               ┃
┃                                                                                                 ┃
┃  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;      ┃
┃  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.      ┃
┃  See the GNU Lesser General Public License for more details.                                    ┃
┃                                                                                                 ┃
┃  You should have received a copy of the GNU Lesser General Public License along with this       ┃
┃  program.   If not, see <http://www.gnu.org/licenses/>.                                         ┃
┃                                                                                                 ┃
┃  ============================================================================================   ┃
┃                                                                                                 ┃
┃  Dieses Programm ist Freie Software: Sie können es unter den Bedingungen der GNU Lesser         ┃
┃  General Public License, wie von der Free Software Foundation, Version 3 der Lizenz oder        ┃
┃  (nach Ihrer Wahl) jeder neueren veröffentlichten Version, weiter verteilen und/oder            ┃
┃  modifizieren.                                                                                  ┃
┃                                                                                                 ┃
┃  Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch OHNE   ┃
┃  JEDE GEWÄHR,; sogar ohne die implizite Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN        ┃
┃  BESTIMMTEN ZWECK. Siehe die GNU Lesser General Public License für weitere Einzelheiten.        ┃
┃                                                                                                 ┃
┃  Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit diesem Programm      ┃
┃  erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.                             ┃
┃                                                                                                 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

ToDo:
━━━━━

*/

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Includes                                                                                  │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
#include "SmithBasics.h"
#include <cmath>
//#include "ui_smithchart.h"

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Defines                                                                                   │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
//#define GETSMITHLABELPOS /* define to move smith chart labels and read positions in debugger */
//#define GETGAMMALABELPOS /* define to move gamma chart labels and read positions in debugger */

/*
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                                                 ┃
┃       SmithBasics                                                                               ┃
┃                                                                                                 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
*/

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Constructors and Destructors                                                              │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
SmithBasics::SmithBasics()
= default;

SmithBasics::~SmithBasics()
{
   delete scene ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       init_graphics_view                                                                        │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Initialize pointer to QGraphicsView                                                             │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void SmithBasics::init_graphics_view(QGraphicsView *qgv)
{
   if (qgv != nullptr)
   {
      graphics_view = qgv ;
      delete scene ; /* cleanup, this function may be called multiple times */
      scene = new GraphicsScene() ; /* create scene, inherited from QGraphicsScene */
      graphics_view->setScene(scene) ;                             /* assign QGraphicsView window defined by QtCreator to scene */
      graphics_view->setRenderHint(QPainter::Antialiasing) ;       /* use antialiasing */
   }
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Wrapper functions                                                                         │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Functions to access private members of SmithBasics and GraphicsScene functions.                 │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void SmithBasics::DrawSmithchart(double real_z0) {scene->DrawSmithchart(real_z0) ;}
void SmithBasics::DrawGamma() {scene->DrawGamma() ;}
QRectF SmithBasics::sceneRect() {return(scene->sceneRect()) ;}
void SmithBasics::clear() {scene->clear() ;}
bool SmithBasics::isOpen() {return(is_open) ;}
void SmithBasics::setOpen() {is_open = true ;}
void SmithBasics::setClosed() {is_open = false ;}
void SmithBasics::updateMarker(complex_dbl *gamma) {if (is_open) scene->updateMarker(gamma) ;}
void SmithBasics::updateSWR(double *swr, int count) {if (is_open) scene->updateSceneSWR(swr, count) ;}
void SmithBasics::addSwrItems(int count) {if (is_open) scene->addSceneSwrItems(count) ;}
void SmithBasics::addMarker(bool moveable) {if (is_open) scene->addSceneMarker(moveable) ;}
void SmithBasics::AddParallelImp(complex_dbl *imp, complex_dbl *parImp) {if (is_open) scene->AddParallelImp(imp, parImp) ;}
void SmithBasics::AddSerialImp(complex_dbl *imp, complex_dbl *serImp) {if (is_open) scene->AddSerialImp(imp, serImp) ;}
void SmithBasics::RemoveImp(int num) {if (is_open) scene->RemoveImp(num) ;}
void SmithBasics::RemoveImp() {if (is_open) scene->RemoveImp() ;}
void SmithBasics::PrintInfo(const QString& text, int location) {if (is_open) scene->PrintInfo(text, location) ;}
void SmithBasics::ClearInfo(int location) {if (is_open) scene->ClearInfo(location) ;}
void SmithBasics::set_opacity(qreal op) {scene->set_opacity(op) ;}
void SmithBasics::setGamma(complex_dbl gamma) {scene->setGamma(gamma) ;}
void SmithBasics::newZ0(qreal newZ0R) {scene->updateSmithLabels(newZ0R) ;}
int  SmithBasics::get_rescount() {return(scene->resistances.size()) ;}
qreal SmithBasics::get_res(int index) {return(scene->resistances.at(index)) ;}

/*
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                                                 ┃
┃       GraphicsScene                                                                             ┃
┃                                                                                                 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
*/

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       DrawSmithchart                                                                            │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Draw Smith chart                                                                                │
│                                                                                                 │
│ This function draws the entire smith chart and stores all items in the smithgroup item group.   │
│ It sets the opacity of the group to 1.0, which is fully opaque.                                 │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::DrawSmithchart(double real_z0)
{
int ivar = 0;
int jvar = 0;
int jmax = 0;
int i ;
qreal scale = NAN;
complex_dbl my_y = {0.0, 0.0};     /* local admittance */
complex_dbl my_z = {0.0, 0.0};     /* local impedance */
complex_dbl my_gamma = {0.0, 0.0}; /* local gamma */
QList <qreal> q_reslist ;
QBrush impText(QColorConstants::Svg::red);
QBrush admText(QColorConstants::Svg::blue);
QPen blackpen(Qt::black);
QPen impedance(Qt::red);
QPen admittance(Qt::blue);
QFont legend;
qreal startangle ;
qreal inc_angle ;
bool line_started ;
bool line_completed ;
//int minindex = 0 ; /* index in q_reslist to end inner lines (to avoid too dense drawing) */
int maxindex = 5 ; /* index in q_reslist to end inner lines (to avoid too dense drawing) */

   z0 = {real_z0, 0.0} ;

   q_reslist.clear() ;
   q_reslist.append( real(z0) /  5.0) ;
   q_reslist.append( real(z0) /  2.0) ;
   q_reslist.append( real(z0)       ) ;
   q_reslist.append( real(z0) *  2.0) ;
   q_reslist.append( real(z0) *  4.0) ;
   q_reslist.append( real(z0) * 10.0) ;
   q_reslist.append(-real(z0) /  5.0) ;
   q_reslist.append(-real(z0) /  2.0) ;
   q_reslist.append(-real(z0)       ) ;
   q_reslist.append(-real(z0) *  2.0) ;
   q_reslist.append(-real(z0) *  4.0) ;
   q_reslist.append(-real(z0) * 10.0) ;

   clear() ; /* Removes and deletes (!) all items from the scene */
   swr_list.clear() ; /* clear list of SWR circles */
   match_list.clear() ; /* clear list of matches */
   smithitems.clear() ; /* clear list of smithchart items */
   smithlabelitems.clear() ; /* clear list of smith chart label items */

   blackpen.setWidth(1);
   impedance.setWidthF(0.2);
   admittance.setWidthF(0.2);
   setSceneRect(-((SDIAM / 2) + SMARGIN),
                -((SDIAM / 2) + SMARGIN),
                SDIAM + (2 * SMARGIN),
                SDIAM + (2 * SMARGIN));

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                                 │
│ Notes on subsequent Smith Chart construction:                                                   │
│ =============================================                                                   │
│                                                                                                 │
│ All Smith Chart gridlines are constructed from impedances or admittances converted to their     │
│ reflection coefficient gamma, with: gamma=(Zl-Z0)/(Zl+Z0))=((1/Yl)-Z0)/(1/Yl)+Z0).              │
│                                                                                                 │
│ Z0 is assumed to be 50 ohms, the gridlines don't change for different Z0, only the values       │
│ need to be adapted.                                                                             │
│                                                                                                 │
│ Earlier versions of this program drew circles instead of constructing the gridlines from        │
│ impedances or admittances. While that works well and is probably faster, its precondition       │
│ is the knowledge or proof, that the traces are really circles. Even though I believe that       │
│ it is true, I have found no such proof and it doesn't seem self-evident of first sight.         │
│                                                                                                 │
│ In order to have fairly equal lengths for constructing the gridlines of the chart, a list       │
│ of resistances is generated, which are equally spaced on the circumference of a unity circle.   │
│ This list applies strictly only for the outer unity circle, but it is good enough for the       │
│ inner circles.                                                                                  │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/

/*
generate a list of resistances which are equally spaced on the circumference of a
unity circle. That list is used to construct all other circles in the diagram.
*/

   inc_angle = 360.0 / SMITH_NODE_COUNT ;
   startangle = inc_angle / 2.0 ;

   for (i=0; i<SMITH_NODE_COUNT; i++)
   {
      my_gamma.real(cos((i*inc_angle+startangle)*M_PI/180.0)) ;
      my_gamma.imag(sin((i*inc_angle+startangle)*M_PI/180.0)) ;
      my_z = z0 * (complex_1+my_gamma)/(complex_1-my_gamma) ;
      resistances.at(i) = my_z.imag() ;
   }

   /* draw impedances, constant R (red lines) */
   jmax = q_reslist.size() / 2 ; /* use only positive values from the lower half of the list */
   for (jvar = 0; jvar < jmax; jvar++)
   {
      my_z.real(q_reslist.at(jvar)) ;
      gridline.clear();
      line_started = false ;
      for (i=0; i<SMITH_NODE_COUNT; i++)
      {
         my_z.imag(resistances.at(i)) ;
         my_gamma = (my_z - z0) / (my_z + z0) ;
         if (line_started) gridline.lineTo(SDIAM / 2 * real(my_gamma), -SDIAM / 2 * imag(my_gamma)) ;
         else { gridline.moveTo(SDIAM / 2 * real(my_gamma), -SDIAM / 2 * imag(my_gamma)) ; line_started = true ;}
      }
      smithitems.append(addPath(gridline, impedance, Qt::NoBrush)) ;
   }

   /* draw impedances, constant X (red lines) */
   jmax = q_reslist.size() ;
   for (jvar = 0; jvar < jmax; jvar++)
   {
      gridline.clear() ;
      my_z.imag(q_reslist.at(jvar)) ;
      line_started = false ;
      line_completed = false ;
      for (ivar = SMITH_NODE_COUNT/2 - 1; (ivar >= 0) && (!line_completed); ivar--)
      { /* use only positive values from the lower half of the list */
         my_z.real(resistances.at(ivar)) ;

         if (((abs(my_z.imag()) <= q_reslist.at(2))) && (resistances.at(ivar) > q_reslist.at(maxindex)))
         {
            my_z.real(q_reslist.at(maxindex)) ;
            line_completed = true ;
         }

         my_gamma = (my_z - z0) / (my_z + z0) ;
         if (line_started) gridline.lineTo(SDIAM / 2 * real(my_gamma), -SDIAM / 2 * imag(my_gamma)) ;
         else {gridline.moveTo(SDIAM / 2 * real(my_gamma), -SDIAM / 2 * imag(my_gamma)) ; line_started = true ;}
      }
      smithitems.append(addPath(gridline, impedance, Qt::NoBrush)) ;
   }

   /* draw admittances, constant G (blue lines) */
   jmax = q_reslist.size() / 2 ; /* use only positive values from the lower half of the list */
   for (jvar = 0; jvar < jmax; jvar++)
   {
      my_y.real(1.0/q_reslist.at(jvar)) ;
      gridline.clear();
      line_started = false ;
      for (i=0; i<SMITH_NODE_COUNT; i++)
      {
         my_y.imag(1.0/resistances.at(i)) ;
         my_gamma = (complex_1/my_y - z0) / (complex_1/my_y + z0) ;
         if (line_started) gridline.lineTo(SDIAM / 2 * real(my_gamma), -SDIAM / 2 * imag(my_gamma)) ;
         else { gridline.moveTo(SDIAM / 2 * real(my_gamma), -SDIAM / 2 * imag(my_gamma)) ; line_started = true ;}
      }
      smithitems.append(addPath(gridline, admittance, Qt::NoBrush)) ;
   }

   /* draw admittances, constant B (blue lines) */
   jmax = q_reslist.size() ;
   for (jvar = 0; jvar < jmax; jvar++)
   {
      gridline.clear() ;
      my_y.imag(1.0/q_reslist.at(jvar)) ;
      line_started = false ;
      line_completed = false ;
      for (ivar = 0; (ivar < SMITH_NODE_COUNT/2) && (!line_completed); ivar++)
      { /* use only positive values from the lower half of the list */
         my_y.real(1.0/resistances.at(ivar)) ;

//         if ((resistances.at(ivar) < 10.0) && (abs(q_reslist.at(jvar)) > 50.0))
         if ((resistances.at(ivar) < q_reslist.at(0)) && (abs(q_reslist.at(jvar)) > q_reslist.at(2)))
         {
            my_y.real(1.0/q_reslist.at(0)) ;
            line_completed = true ;
         }

         my_gamma = (complex_1/my_y - z0) / (complex_1/my_y + z0) ;
         if (line_started) gridline.lineTo(SDIAM / 2 * real(my_gamma), -SDIAM / 2 * imag(my_gamma)) ;
         else {gridline.moveTo(SDIAM / 2 * real(my_gamma), -SDIAM / 2 * imag(my_gamma)) ; line_started = true ;}
      }
      smithitems.append(addPath(gridline, admittance, Qt::NoBrush)) ;
   }

   /* display legend */

   legend.setPointSize(4);
   legend.setWeight(QFont::Normal);
   scale = SDIAM / 200.0; /* scale, full scale is -100.0 to +100.0 */

/*
If "GETSMITHLABELPOS" is defined, labels can be moved by mouse and their positions
can be read in the debugger if a breakpoint is set in updateSceneSWR function.

t.b.d.: labels should have an opaque background

*/

/* constant R (unit: Ω) */
   smithlabelitems.append(print(QString("%L1Ω").arg(q_reslist[ 0], 0, 'f', 0),    &legend, &impText,    6.49 * scale,   77.90 * scale)) ;
   smithlabelitems.append(print(QString("%L1Ω").arg(q_reslist[ 1], 0, 'f', 0),    &legend, &impText,   32.98 * scale,   61.49 * scale)) ;
   smithlabelitems.append(print(QString("%L1Ω").arg(q_reslist[ 2], 0, 'f', 0),    &legend, &impText,   51.50 * scale,   44.08 * scale)) ;
   smithlabelitems.append(print(QString("%L1Ω").arg(q_reslist[ 3], 0, 'f', 0),    &legend, &impText,   59.70 * scale,   27.56 * scale)) ;
   smithlabelitems.append(print(QString("%L1Ω").arg(q_reslist[ 4], 0, 'f', 0),    &legend, &impText,   73.47 * scale,   13.51 * scale)) ;
   smithlabelitems.append(print(QString("%L1Ω").arg(q_reslist[ 5], 0, 'f', 0),    &legend, &impText,   86.40 * scale,    2.95 * scale)) ;


//   smithlabelitems.append(print( "10Ω",    &legend, &impText,    6.49 * scale,   77.90 * scale)) ;
//   smithlabelitems.append(print( "25Ω",    &legend, &impText,   32.98 * scale,   61.49 * scale)) ;
//   smithlabelitems.append(print( "50Ω",    &legend, &impText,   51.50 * scale,   44.08 * scale)) ;
//   smithlabelitems.append(print("100Ω",    &legend, &impText,   59.70 * scale,   27.56 * scale)) ;
//   smithlabelitems.append(print("200Ω",    &legend, &impText,   73.47 * scale,   13.51 * scale)) ;
//   smithlabelitems.append(print("500Ω",    &legend, &impText,   86.40 * scale,    2.95 * scale)) ;

/* constant G */
   smithlabelitems.append(print(QString("%L1mS").arg(1000.0/q_reslist[ 0], 0, 'f', 1),   &legend, &admText,  -86.93 * scale,  -21.87 * scale)) ;
   smithlabelitems.append(print(QString("%L1mS").arg(1000.0/q_reslist[ 1], 0, 'f', 1),   &legend, &admText,  -74.40 * scale,  -38.80 * scale)) ;
   smithlabelitems.append(print(QString("%L1mS").arg(1000.0/q_reslist[ 2], 0, 'f', 1),   &legend, &admText,  -65.11 * scale,  -55.17 * scale)) ;
   smithlabelitems.append(print(QString("%L1mS").arg(1000.0/q_reslist[ 3], 0, 'f', 1),   &legend, &admText,  -45.94 * scale,  -71.35 * scale)) ;
   smithlabelitems.append(print(QString("%L1mS").arg(1000.0/q_reslist[ 4], 0, 'f', 1),   &legend, &admText,  -19.32 * scale,  -84.85 * scale)) ;
   smithlabelitems.append(print(QString("%L1mS").arg(1000.0/q_reslist[ 5], 0, 'f', 1),   &legend, &admText,   16.43 * scale,  -92.33 * scale)) ;

//   smithlabelitems.append(print("100mS",   &legend, &admText,  -86.93 * scale,  -21.87 * scale)) ;
//   smithlabelitems.append(print( "40mS",   &legend, &admText,  -72.06 * scale,  -38.28 * scale)) ;
//   smithlabelitems.append(print( "20mS",   &legend, &admText,  -61.98 * scale,  -55.17 * scale)) ;
//   smithlabelitems.append(print( "10mS",   &legend, &admText,  -45.42 * scale,  -71.09 * scale)) ;
//   smithlabelitems.append(print(  "5mS",   &legend, &admText,  -19.32 * scale,  -84.85 * scale)) ;
//   smithlabelitems.append(print(  "2mS",   &legend, &admText,   16.43 * scale,  -92.33 * scale)) ;

/* constant X */
   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[ 0], 0, 'f', 0),   &legend, &impText, -101.16 * scale,  -45.59 * scale)) ;
   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[ 1], 0, 'f', 0),   &legend, &impText,  -63.71 * scale,  -89.25 * scale)) ;
   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[ 2], 0, 'f', 0),   &legend, &impText,    1.54 * scale, -105.81 * scale)) ;
   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[ 3], 0, 'f', 0),   &legend, &impText,   63.58 * scale,  -81.93 * scale)) ;
   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[ 4], 0, 'f', 0),   &legend, &impText,   90.99 * scale,  -49.02 * scale)) ;
   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[ 5], 0, 'f', 0),   &legend, &impText,   99.79 * scale,  -20.08 * scale)) ;

   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[ 6], 0, 'f', 0),  &legend, &impText, -102.70 * scale,   40.38 * scale)) ;
   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[ 7], 0, 'f', 0),  &legend, &impText,  -64.23 * scale,   84.25 * scale)) ;
   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[ 8], 0, 'f', 0),  &legend, &impText,    3.45 * scale,  100.73 * scale)) ;
   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[ 9], 0, 'f', 0),  &legend, &impText,   64.84 * scale,   76.92 * scale)) ;
   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[10], 0, 'f', 0),  &legend, &impText,   91.72 * scale,   42.50 * scale)) ;
   smithlabelitems.append(print(QString("%L1jΩ").arg(q_reslist[11], 0, 'f', 0),  &legend, &impText,   99.69 * scale,   14.96 * scale)) ;

//   smithlabelitems.append(print( "10jΩ",   &legend, &impText, -101.16 * scale,  -45.59 * scale)) ;
//   smithlabelitems.append(print( "25jΩ",   &legend, &impText,  -63.71 * scale,  -89.25 * scale)) ;
//   smithlabelitems.append(print( "50jΩ",   &legend, &impText,    2.32 * scale, -105.55 * scale)) ;
//   smithlabelitems.append(print("100jΩ",   &legend, &impText,   63.58 * scale,  -81.93 * scale)) ;
//   smithlabelitems.append(print("200jΩ",   &legend, &impText,   90.99 * scale,  -49.02 * scale)) ;
//   smithlabelitems.append(print("500jΩ",   &legend, &impText,   99.79 * scale,  -20.08 * scale)) ;
//
//   smithlabelitems.append(print( "-10jΩ",  &legend, &impText, -102.70 * scale,   40.38 * scale)) ;
//   smithlabelitems.append(print( "-25jΩ",  &legend, &impText,  -64.23 * scale,   84.25 * scale)) ;
//   smithlabelitems.append(print( "-50jΩ",  &legend, &impText,    3.45 * scale,  100.73 * scale)) ;
//   smithlabelitems.append(print("-100jΩ",  &legend, &impText,   64.84 * scale,   76.92 * scale)) ;
//   smithlabelitems.append(print("-200jΩ",  &legend, &impText,   91.72 * scale,   42.50 * scale)) ;
//   smithlabelitems.append(print("-500jΩ",  &legend, &impText,   99.69 * scale,   14.96 * scale)) ;

/* constant B */
   smithlabelitems.append(print(QString("%L1jmS").arg(-1000.0/q_reslist[ 0], 0, 'f', 1), &legend, &admText, -113.44 * scale,  -38.50 * scale)) ;
   smithlabelitems.append(print(QString("%L1jmS").arg(-1000.0/q_reslist[ 1], 0, 'f', 1), &legend, &admText,  -79.70 * scale,  -82.55 * scale)) ;
   smithlabelitems.append(print(QString("%L1jmS").arg(-1000.0/q_reslist[ 2], 0, 'f', 1), &legend, &admText,  -15.71 * scale, -105.55 * scale)) ;
   smithlabelitems.append(print(QString("%L1jmS").arg(-1000.0/q_reslist[ 3], 0, 'f', 1), &legend, &admText,   56.20 * scale,  -88.24 * scale)) ;
   smithlabelitems.append(print(QString("%L1jmS").arg(-1000.0/q_reslist[ 4], 0, 'f', 1), &legend, &admText,   87.48 * scale,  -54.13 * scale)) ;
   smithlabelitems.append(print(QString("%L1jmS").arg(-1000.0/q_reslist[ 5], 0, 'f', 1), &legend, &admText,   98.19 * scale,  -25.98 * scale)) ;

   smithlabelitems.append(print(QString("%L1jmS").arg(1000.0/q_reslist[ 0], 0, 'f', 1), &legend, &admText, -112.13 * scale,   33.86 * scale)) ;
   smithlabelitems.append(print(QString("%L1jmS").arg(1000.0/q_reslist[ 1], 0, 'f', 1), &legend, &admText,  -77.59 * scale,   77.51 * scale)) ;
   smithlabelitems.append(print(QString("%L1jmS").arg(1000.0/q_reslist[ 2], 0, 'f', 1), &legend, &admText,  -13.23 * scale,  100.94 * scale)) ;
   smithlabelitems.append(print(QString("%L1jmS").arg(1000.0/q_reslist[ 3], 0, 'f', 1), &legend, &admText,   54.18 * scale,   84.52 * scale)) ;
   smithlabelitems.append(print(QString("%L1jmS").arg(1000.0/q_reslist[ 4], 0, 'f', 1), &legend, &admText,   88.33 * scale,   50.04 * scale)) ;
   smithlabelitems.append(print(QString("%L1jmS").arg(1000.0/q_reslist[ 5], 0, 'f', 1), &legend, &admText,   99.06 * scale,   21.76 * scale)) ;

//   smithlabelitems.append(print("-100jmS", &legend, &admText, -109.80 * scale,  -37.98 * scale)) ;
//   smithlabelitems.append(print( "-40jmS", &legend, &admText,  -76.57 * scale,  -82.03 * scale)) ;
//   smithlabelitems.append(print( "-20jmS", &legend, &admText,  -13.37 * scale, -105.55 * scale)) ;
//   smithlabelitems.append(print( "-10jmS", &legend, &admText,   56.20 * scale,  -88.24 * scale)) ;
//   smithlabelitems.append(print(  "-5jmS", &legend, &admText,   87.48 * scale,  -54.13 * scale)) ;
//   smithlabelitems.append(print(  "-2jmS", &legend, &admText,   98.19 * scale,  -25.98 * scale)) ;
//
//   smithlabelitems.append(print( "100jmS", &legend, &admText, -107.97 * scale,   33.86 * scale)) ;
//   smithlabelitems.append(print(  "40jmS", &legend, &admText,  -74.20 * scale,   77.51 * scale)) ;
//   smithlabelitems.append(print(  "20jmS", &legend, &admText,  -13.23 * scale,  100.94 * scale)) ;
//   smithlabelitems.append(print(  "10jmS", &legend, &admText,   54.18 * scale,   84.52 * scale)) ;
//   smithlabelitems.append(print(   "5jmS", &legend, &admText,   88.33 * scale,   50.04 * scale)) ;
//   smithlabelitems.append(print(   "2jmS", &legend, &admText,   99.06 * scale,   21.76 * scale)) ;

   /* draw outer border */
   smithitems.append(addEllipse(-SDIAM / 2, -SDIAM / 2, SDIAM, SDIAM, blackpen, Qt::NoBrush)) ;

   /* draw horizontal line */
   blackpen.setWidthF(0.3) ;
   smithitems.append(addLine(-SDIAM / 2, 0, SDIAM / 2, 0, blackpen)) ;

/* append all smithlabelitems to smithitems */
/*   smithitems.append(smithlabelitems) ; is not working */
#ifndef GETSMITHLABELPOS
   for (i=0; i<smithlabelitems.size(); i++) smithitems.append(smithlabelitems.at(i)) ;
#endif

   smithgroup = createItemGroup(smithitems) ;
   smithgroup->setOpacity(1.0) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       DrawGamma                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Draw Gamma                                                                                      │
│                                                                                                 │
│ This function draws the gamma chart and stores all items in the gammagroup item group.          │
│ It sets the opacity of the group to 0.0, which is fully transparent.                            │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::DrawGamma()
{
int i = 0 ;
qreal len = NAN ;
qreal posx = NAN;
qreal posy = NAN;
qreal scale = NAN;
QBrush legendText(QColorConstants::Svg::blue);
QPen blackpen(Qt::black);
QPen markerlinepen(Qt::darkBlue);
QFont legend;

   gammalabelitems.clear() ;    /* clear list of gamma label items */
   gammaitems.clear() ;         /* clear list of gamma items */

   blackpen.setWidth(1) ;

/*
If "GETGAMMALABELPOS" is defined, labels can be moved by mouse and their positions
can be read in the debugger if a breakpoint is set in updateSceneSWR function.

t.b.d.: labels should have an opaque background

*/

   legend.setPointSize(4);
   legend.setWeight(QFont::Normal);
   scale = SDIAM / 200.0; /* scale, full scale is -100.0 to +100.0 */

/* display legend */
   gammalabelitems.append(print(   "-1",        &legend, &legendText, -105.21 * scale,   -3.00 * scale)) ;
   gammalabelitems.append(print( "-0.5",        &legend, &legendText,  -58.54 * scale,    1.00 * scale)) ;
   gammalabelitems.append(print(    "0",        &legend, &legendText,    1.52 * scale,    0.60 * scale)) ;
   gammalabelitems.append(print( "+0.5",        &legend, &legendText,   52.06 * scale,    1.00 * scale)) ;
   gammalabelitems.append(print(   "+1",        &legend, &legendText,  101.87 * scale,   -3.00 * scale)) ;

   gammalabelitems.append(print(   "+j",        &legend, &legendText,   -2.00 * scale, -106.51 * scale)) ;
   gammalabelitems.append(print("+0.5j",        &legend, &legendText,   -9.99 * scale,  -56.00 * scale)) ;
   gammalabelitems.append(print("-0.5j",        &legend, &legendText,   -9.62 * scale,   50.30 * scale)) ;
   gammalabelitems.append(print(   "-j",        &legend, &legendText,   -0.73 * scale,  100.60 * scale)) ;

   gammalabelitems.append(print("| Γ |=M=0.25", &legend, &legendText,   20.50 * scale,  -20.02 * scale)) ;
   gammalabelitems.append(print("| Γ |=M=0.5" , &legend, &legendText,   42.54 * scale,  -32.70 * scale)) ;
   gammalabelitems.append(print("| Γ |=M=0.75", &legend, &legendText,   64.48 * scale,  -44.41 * scale)) ;

   /* draw inner polar grids */
   markerlinepen.setWidthF(0.4) ;
   markerlinepen.setStyle(Qt::DotLine) ;
   gammaitems.append(addEllipse((-SDIAM * 1) / 8, (-SDIAM * 1) / 8, (SDIAM * 1) / 4, (SDIAM * 1) / 4, markerlinepen, Qt::NoBrush)) ;
   gammaitems.append(addEllipse((-SDIAM * 3) / 8, (-SDIAM * 3) / 8, (SDIAM * 3) / 4, (SDIAM * 3) / 4, markerlinepen, Qt::NoBrush)) ;
   markerlinepen.setWidthF(0.6) ;
   gammaitems.append(addEllipse((-SDIAM * 2) / 8, (-SDIAM * 2) / 8, (SDIAM * 2) / 4, (SDIAM * 2) / 4, markerlinepen, Qt::NoBrush)) ;

   /* draw outer border */
   gammaitems.append(addEllipse(-SDIAM / 2, -SDIAM / 2, SDIAM, SDIAM, blackpen, Qt::NoBrush)) ;

   /* draw coordinate system */
   blackpen.setWidthF(0.3) ;
   gammaitems.append(addLine(-SDIAM / 2, 0, SDIAM / 2, 0, blackpen)) ;
   gammaitems.append(addLine(0, SDIAM / 2, 0, -SDIAM / 2, blackpen)) ;

/* add ticks */
   for (i=1; i<10; i++)
   {
      len = 2.0 ;
      if (i==5) len = 5.0 ;
      posx = -SDIAM / 2 + i * SDIAM / 20 ;
      gammaitems.append(addLine(posx, len/2.0, posx, -len/2.0, blackpen)) ;
      posx = i * SDIAM / 20 ;
      gammaitems.append(addLine(posx, len/2.0, posx, -len/2.0, blackpen)) ;
      posy = -SDIAM / 2 + i * SDIAM / 20 ;
      gammaitems.append(addLine(-len/2.0, posy, len/2.0, posy, blackpen)) ;
      posy = i * SDIAM / 20 ;
      gammaitems.append(addLine(-len/2.0, posy, len/2.0, posy, blackpen)) ;
   }

/* add line to marker */
   markerlinepen.setWidthF(1.5) ;
   markerlinepen.setStyle(Qt::SolidLine) ;
   markerline = addLine(-0.1, 0.0, 0.1, 0.0, markerlinepen) ;
   gammaitems.append(markerline) ;

/* append all gammalabelitems to gammaitems */
#ifndef GETGAMMALABELPOS
   for (i=0; i<gammalabelitems.size(); i++) gammaitems.append(gammalabelitems.at(i)) ;
#endif

   gammagroup = createItemGroup(gammaitems) ;
   gammagroup->setOpacity(0.0) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       updateSmithLabels                                                                         │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Update labels of smith chart because Z0 has changed.                                            │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::updateSmithLabels(qreal newZ0R)
{
   z0.real(newZ0R) ;
   z0.imag(0.0) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       print                                                                                     │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Display text at position x and y. Use specified font and brush.                                 │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
QGraphicsSimpleTextItem *GraphicsScene::print(const QString& text, QFont *font, QBrush *brush, qreal posx, qreal posy)
{
QGraphicsSimpleTextItem *mytext = nullptr ;
   mytext = addSimpleText(text, *font) ;
   mytext->setPos(posx, posy) ;
   mytext->setBrush(*brush) ;
#ifdef GETSMITHLABELPOS
   mytext->setFlags(QGraphicsItem::ItemIsMovable) ;
#endif
#ifdef GETGAMMALABELPOS
   mytext->setFlags(QGraphicsItem::ItemIsMovable) ;
#endif
   return(mytext) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       PrintInfo                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Display info text at predefined location. Use predefined font and brush.                        │
│                                                                                                 │
│ <location> specifies the quadrant for the diaply:                                               │
│ 1: upper right, 2: upper left, 3:lower left, 4: lower right                                     │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::PrintInfo(const QString& text, int location)
{
QBrush infoBrush(QColorConstants::Svg::darkblue) ;
QFont infoFont ;
qreal posx ;
qreal posy ;
qreal scale ;
   location-- ;
   switch(location)
   {
   case 0:  posx =   37.0 ; posy = -105.0 ; break ;
   case 1:  posx = -102.0 ; posy = -105.0 ; break ;
   case 2:  posx = -102.0 ; posy =   93.0 ; break ;
   case 3:  posx =   37.0 ; posy =   93.0 ; break ;
   default: posx =    0.0 ; posy =    0.0 ; break ;
   }

   switch(location)
   {
   case 0:
   case 1:
   case 2:
   case 3:
      if (infoitem.at(location) == nullptr)
      {
         infoFont.setPointSize(8) ;
         infoFont.setWeight(QFont::Bold) ;
         scale = SDIAM / 200.0; /* scale, full scale is -100.0 to +100.0 */
         infoitem.at(location) = addSimpleText("", infoFont) ;
         infoitem.at(location)->setPos(posx * scale, posy * scale) ;
         infoitem.at(location)->setBrush(infoBrush);
      }
      infoitem.at(location)->setText(text) ;
   break ;
   }
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       ClearInfo                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Clear info text at predefined location.                                                         │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::ClearInfo(int location)
{
   location-- ;
   switch(location)
   {
   case 0:
   case 1:
   case 2:
   case 3:
      if (infoitem.at(location) != nullptr) infoitem.at(location)->setText("") ;
   break ;
   }
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       set_opacity                                                                               │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Set opacity of smith chart and gamma chart                                                      │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::set_opacity(qreal op)
{
   smithgroup->setOpacity(op) ;
   gammagroup->setOpacity(1.0-op) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       addSceneSwrItems()                                                                        │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Add <count> SWR items                                                                           │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::addSceneSwrItems(int count)
{
int i ;
QGraphicsEllipseItem *swr_item = nullptr ;
   swr_list.clear() ; /* clear list of SWR circles (should already be cleared but just in case) */
   for (i=0; i<count; i++)
   {
      swr_item = new QGraphicsEllipseItem() ;
      swr_list.append(swr_item) ;
      swr_item->setRect(0, 0, 0, 0);
      addItem(swr_item);
      swr_item->hide() ;
   }
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       updateSceneSWR()                                                                          │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Update SWR circles according to swr.                                                            │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::updateSceneSWR(double *swr, int count)
{
qreal abs_gamma = NAN ; /* abs(Gamma) = (SWR-1)/(SWR+1) */
qreal radius = NAN ;    /* Radius of SWR circle */
QColor swr_color ;
QPen blackpen ;
int i ;

   swr_color.setRgb(Qt::black) ;
   swr_color.setAlpha(100) ;
   blackpen.setColor(swr_color) ;
   blackpen.setWidthF(0.8) ;
   blackpen.setStyle(Qt::DotLine) ;

   for (i=0; i<count; i++)
   {
      if (swr[i] > 1.0)
      {
         abs_gamma = (swr[i] - 1) / (swr[i] + 1);
         radius = abs_gamma * SDIAM / 2;
         swr_list.at(i)->setPen(blackpen);
         swr_list.at(i)->setRect(-radius, -radius, 2 * radius, 2 * radius);
         swr_list.at(i)->show() ;
      }
      else swr_list.at(i)->hide() ;
   }

#ifdef GETSMITHLABELPOS
/* temporary test code */
QList <qreal> posx ;
QList <qreal> posy ;
   for (i=0; i<smithlabelitems.size(); i++)
   {
      posx.append(smithlabelitems.at(i)->x()*200.0/SDIAM) ;
      posy.append(smithlabelitems.at(i)->y()*200.0/SDIAM) ;
   }
   count = i ; /* set breakpoint here */
#endif

#ifdef GETGAMMALABELPOS
/* temporary test code */
QList <qreal> posxg ;
QList <qreal> posyg ;
   for (i=0; i<gammalabelitems.size(); i++)
   {
      posxg.append(gammalabelitems.at(i)->x()*200.0/SDIAM) ;
      posyg.append(gammalabelitems.at(i)->y()*200.0/SDIAM) ;
   }
   count = i ; /* set breakpoint here */
#endif

}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       addSceneMarker()                                                                          │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Add marker                                                                                      │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::addSceneMarker(bool moveable)
{
   markeritem = new markerItem() ;       /* marker */
   markeritem->scene = this ;

   /* generate marker item */
   QPen markerpen(QColorConstants::Svg::darkgreen) ;
   markerpen.setWidthF(0.4) ;
   markeritem->setPen(markerpen) ;

   marker.clear() ;
   marker.moveTo(-5, -5) ;
   marker.lineTo(5, 5) ;
   marker.moveTo(-5, 5) ;
   marker.lineTo(5, -5) ;
   marker.addEllipse(-2, -2, 4, 4) ;

   markeritem->setPath(marker) ;
   if (moveable) markeritem->setFlags(QGraphicsItem::ItemIsMovable) ;
   addItem(markeritem) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       AddParallelImp                                                                            │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Add Match Line for a parallel impedance                                                         │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::AddParallelImp(complex_dbl *imp, complex_dbl *parImp)
{
QGraphicsPathItem *matchitem = nullptr ;
QPainterPath matchpath ;
QPointF point ;
complex_dbl increment ;
complex_dbl parAdm ;
int i = 0 ;
complex_dbl zc_tmp = {0.0, 0.0} ;
complex_dbl yc_parallel = {0.0, 0.0} ;

   matchitem = new QGraphicsPathItem() ; /* create new item */
   matchpath.clear() ;

/* generate path */
   parAdm = complex_1 / *parImp ;
   increment = parAdm / ((double) NODE_COUNT) ;

   zc_tmp = *imp ;
   getPos(&point, imp) ;
   matchpath.moveTo(point) ;

   for (i=1; i<=NODE_COUNT; i++)
   {
      yc_parallel = ((double) i) * increment ;
      zc_tmp = complex_1 / ((complex_1 / *imp) + yc_parallel) ;
      getPos(&point, &zc_tmp) ;
      matchpath.lineTo(point) ;
   }

   *imp = zc_tmp ;

   QPen matchpen(QColorConstants::Svg::darkgreen) ;
   matchpen.setWidthF(1.0) ;

   matchitem->setPen(matchpen) ;
   matchitem->setPath(matchpath) ;
   matchitem->show() ;

   match_list.append(matchitem) ;

/* match curves on top */
   addItem(matchitem) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       AddSerialImp                                                                              │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Add Match Line for a serial impedance                                                           │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::AddSerialImp(complex_dbl *imp, complex_dbl *serImp)
{
QGraphicsPathItem *matchitem = nullptr ;
QPainterPath matchpath ;
QPointF point ;
complex_dbl increment = NAN ;
int i = 0 ;
   matchitem = new QGraphicsPathItem() ; /* create new item */
   matchpath.clear() ;

/* generate path */
   increment = *serImp / ((double) NODE_COUNT) ;

   getPos(&point, imp) ;
   matchpath.moveTo(point) ;

   for (i=0; i<NODE_COUNT; i++)
   {
      *imp = *imp + increment ;
      getPos(&point, imp) ;
      matchpath.lineTo(point) ;
   }

   QPen matchpen(QColorConstants::Svg::darkred) ;
   matchpen.setWidthF(1.0) ;
   matchitem->setPen(matchpen) ;
   matchitem->setPath(matchpath) ;
   matchitem->show() ;

   match_list.append(matchitem) ;

/* match curves on top */
   addItem(matchitem) ;

}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       RemoveImp                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Remove selected Match Line                                                                      │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::RemoveImp(int num)
{
   if (match_list.size() >= num)
   {
      removeItem(match_list.at(num-1)) ;
      match_list.removeAt(num-1) ;
   }
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       RemoveImp                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Remove all Match Lines                                                                          │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::RemoveImp()
{
   while (!match_list.empty())
   {
      removeItem(match_list.last()) ;
      match_list.removeLast() ;
   }
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       updateMarker()                                                                            │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Update marker position                                                                          │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::updateMarker(complex_dbl *gamma) const
{
qreal posx = NAN;
qreal posy = NAN;

   if (abs(*gamma) <= 1.0)
   {
      posx = real(*gamma) * SDIAM / 2;
      posy = -imag(*gamma) * SDIAM / 2;
      markeritem->setPos(posx, posy);
      markerline->setLine(0.0, 0.0, posx, posy) ;
   }
}


/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       markerDragged()                                                                           │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Marker was dragged by user                                                                      │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::markerDragged(QPointF /* pos */)
{
qreal posx = NAN;
qreal posy = NAN;
complex_dbl gamma = {0.0, 0.0} ;     /* complex gamma */
QPen errorpen(Qt::red) ;
QPen normalpen(Qt::darkBlue);

   posx = 2.0 * markeritem->x() / SDIAM ;
   posy = -2.0 * markeritem->y() / SDIAM ;
   gamma = {posx, posy} ;
/* accept a few invalid values, which may occur during manual editing */
   if ((abs(gamma.real()) <= 1.0) && ((abs(gamma.imag()) <= 1.0)))
   { /* ignore if marker is outside of unity circle */
      if (abs(gamma) > 1.0)
         markerline->setPen(errorpen) ;
      else
         markerline->setPen(normalpen) ;
      markerline->setLine(0.0, 0.0, markeritem->x(), markeritem->y()) ;
      emit NewGamma(gamma) ;
   }
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       setGamma()                                                                                │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Set new gamma value, update marker position                                                     │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::setGamma(complex_dbl gamma)
{
QPointF pos ;
   pos.setX(real(gamma) * SDIAM / 2) ;
   pos.setY(-imag(gamma) * SDIAM / 2) ;
   markeritem->setPos(pos) ;
   markerDragged(pos) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       getPos()                                                                                  │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ Update marker position                                                                          │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void GraphicsScene::getPos(QPointF *point, complex_dbl *impedance)
{
complex_dbl gamma ;
   gamma = (*impedance-z0) / (*impedance+z0) ;
   point->setX(real(gamma) * SDIAM / 2) ;
   point->setY(-imag(gamma) * SDIAM / 2) ;
}

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       mouseMoveEvent()                                                                          │
├─────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                 │
│ The context menue was called.                                                                   │
│                                                                                                 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
void markerItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
   if ((event->buttons() & Qt::LeftButton) != 0)
   { /* drag only if left button is pressed */
      scene->markerDragged(event->scenePos()) ;
   }
   QGraphicsItem::mouseMoveEvent(event) ;
}


