Lab 12-2: Simple Complex Number Geometry Transformation (40%)

  • 輸入:
    1. 幾何圖形
    2. char 格式輸入幾何圖形形狀,包含三角形 (t)、四邊形 (q)、多邊形 (p)、圓形 (c),一行輸入一個幾何圖形
    3. unsigned int 格式輸入幾何圖形的頂點數,一行輸入一個正整數
      1. 三角形:3
      2. 四邊形:4
      3. 多邊形:大於 3 的正整數
      4. 圓形:2
    4. double 格式輸入組合幾何圖形的複數的實數及虛數部分,以空格分開,一行輸入一個複數
    5. 輸入幾何圖形形狀及頂點數後依據 2. 的頂點數接著輸入相對應的複數
      1. 三角形:連續輸入三個複數
      2. 四邊形:連續輸入四個複數
      3. 多邊形:連續輸入多個複數
      4. 圓形:連續輸入兩個複數
    6. 幾何變換
    7. char 格式輸入幾何變換字元,包含以 0 點旋轉 (r)、以 0 點縮放 (z)、平移 (m),一行輸入一個幾何變換
    8. double 格式輸入幾何變換的複數的實數及虛數部分,以空格分開,一行輸入一個複數
      1. 0 點旋轉:\(z * (cos(\theta) + sin(\theta)i), norm = 1\)
      2. 0 點縮放:\(z * (r + 0i)\)
      3. 平移:\(z + (x + yi)\)
    9. 輸入幾何變換後須將所有的幾何圖形複數變換
    10. 輸入 Ctrl+D 結束程式
      • Windows 請輸入 Ctrl+Z (會在螢幕上顯示 ^Z) 再輸入 Enter (Format 中的 ) 完成輸入
  • 輸出:
    1. 幾何圖形
      1. 顯示紀錄幾何圖形的形狀、頂點個數及其複數
        1. 格式請參考 Format 中的說明
        2. 頂點順序與輸入順序相同
      2. 複數的格式為 (-)<real result> (+|-) (<imag result>i)
        1. 若虛數部分為 0 則僅顯示實數部分
        2. 若虛數部分小於 0 則中間的 + 要改成 -,並且虛數部分要顯示絕對值
      3. 虛數及實數部分皆以預設 double 格式顯示
    2. 幾何變換
      1. 輸出變換後的所有幾何圖形複數
  • 檔名:lab12-2_<學號>.cpp (e.g. lab12-2_106062802.cpp)

注意事項:

  • 程式不會輸出任何使用者提示,只會輸出程式結果
  • 使用者不需要處理錯誤輸入
  • 請使用 pseudo code 提供的 main 來處理輸入與輸出
  • 程式需要於 10 秒內完成,所有的測資皆會保證於 10 秒內完成

Format

Input

<geometry type>⏎
n⏎
<real 1> <imag 1>⏎
<real 2> <imag 2>⏎
...
<real n> <imag n>⏎
<geometry type>
n
(-)<real 1> (+|-) (<imag 1>i)
(-)<real 2> (+|-) (<imag 2>i)
...
(-)<real n> (+|-) (<imag n>i)

Transformation

<geometry type 1>⏎
n⏎
<real 1> <imag 1>⏎
<real 2> <imag 2>⏎
...
<real n> <imag n>⏎
<geometry type 1>
n
(-)<real 1> (+|-) (<imag 1>i)
(-)<real 2> (+|-) (<imag 2>i)
...
(-)<real n> (+|-) (<imag n>i)
<geometry type 2>⏎
n⏎
<real 1> <imag 1>⏎
<real 2> <imag 2>⏎
...
<real n> <imag n>⏎
<geometry type 2>
n
(-)<real 1> (+|-) (<imag 1>i)
(-)<real 2> (+|-) (<imag 2>i)
...
(-)<real n> (+|-) (<imag n>i)
<geometry transformation type>⏎
(-)<real trans> (+|-) (<imag trans>i)⏎
<geometry type 1>
n
(-)<real 1> (+|-) (<imag 1>i)
(-)<real 2> (+|-) (<imag 2>i)
...
(-)<real n> (+|-) (<imag n>i)
<geometry type 2>
n
(-)<real 1> (+|-) (<imag 1>i)
(-)<real 2> (+|-) (<imag 2>i)
...
(-)<real n> (+|-) (<imag n>i)
...
^Z⏎

Example

Input

Triangle
$ ./a.out
t⏎
3⏎
1.0 2.0⏎
3.0 4.0⏎
5.0 0.0⏎
t
3
1 + 2i
3 + 4i
5
^Z⏎
Quadrilateral
$ ./a.out
q⏎
4⏎
1.0 2.0⏎
3.0 2.0⏎
3.0 4.0⏎
1.0 4.0⏎
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
^Z⏎
Circle
$ ./a.out
c⏎
2⏎
1.0 2.0⏎
3.0 4.0⏎
c
2
1 + 2i
3 + 4i
^Z⏎
Polygon
$ ./a.out
p⏎
5⏎
1.0 0.0⏎
2.0 1.1⏎
-3.0 -2.2⏎
4.3 2.1⏎
-1.2 3.4⏎
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
^Z⏎
Multiple Objects
$ ./a.out
t⏎
3⏎
1.0 2.0⏎
3.0 4.0⏎
5.0 0.0⏎
t
3
1 + 2i
3 + 4i
5
q⏎
4⏎
1.0 2.0⏎
3.0 2.0⏎
3.0 4.0⏎
1.0 4.0⏎
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
c⏎
2⏎
1.0 2.0⏎
3.0 4.0⏎
c
2
1 + 2i
3 + 4i
p⏎
5⏎
1.0 0.0⏎
2.0 1.1⏎
-3.0 -2.2⏎
4.3 2.1⏎
-1.2 3.4⏎
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
^Z⏎

Transformation

Scaling
$ ./a.out
t⏎
3⏎
1.0 2.0⏎
3.0 4.0⏎
5.0 0.0⏎
t
3
1 + 2i
3 + 4i
5
z⏎
2.0 0.0⏎
t
3
2 + 4i
6 + 8i
10
^Z⏎
Translation
$ ./a.out
q⏎
4⏎
1.0 2.0⏎
3.0 2.0⏎
3.0 4.0⏎
1.0 4.0⏎
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
m⏎
3.0 -1.0⏎
q
4
4 + 1i
6 + 1i
6 + 3i
4 + 3i
^Z⏎
Rotation
$ ./a.out
c⏎
2⏎
1.0 2.0⏎
3.0 4.0⏎
c
2
1 + 2i
3 + 4i
r⏎
0.99990604980155 0.013707354604752⏎
c
2
0.972491 + 2.01352i
2.94489 + 4.04075i
^Z⏎
Multiple Transformations
$ ./a.out
p⏎
5⏎
1.0 0.0⏎
2.0 1.1⏎
-3.0 -2.2⏎
4.3 2.1⏎
-1.2 3.4⏎
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
z⏎
2.0 0.0⏎
p
5
2
4 + 2.2i
-6 - 4.4i
8.6 + 4.2i
-2.4 + 6.8i
m⏎
3.0 -1.0⏎
p
5
5 - 1i
7 + 1.2i
-3 - 5.4i
11.6 + 3.2i
0.6 + 5.8i
r⏎
0.99990604980155 0.013707354604752⏎
p
5
5.01324 - 0.931369i
6.98289 + 1.29584i
-2.9257 - 5.44061i
11.555 + 3.3587i
0.520441 + 5.80768i
^Z⏎
Multiple Transformations on Multiple Objects
$ ./a.out
t⏎
3⏎
1.0 2.0⏎
3.0 4.0⏎
5.0 0.0⏎
t
3
1 + 2i
3 + 4i
5
q⏎
4⏎
1.0 2.0⏎
3.0 2.0⏎
3.0 4.0⏎
1.0 4.0⏎
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
c⏎
2⏎
1.0 2.0⏎
3.0 4.0⏎
c
2
1 + 2i
3 + 4i
p⏎
5⏎
1.0 0.0⏎
2.0 1.1⏎
-3.0 -2.2⏎
4.3 2.1⏎
-1.2 3.4⏎
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
z⏎
2.0 0.0⏎
t
3
2 + 4i
6 + 8i
10
q
4
2 + 4i
6 + 4i
6 + 8i
2 + 8i
c
2
2 + 4i
6 + 8i
p
5
2
4 + 2.2i
-6 - 4.4i
8.6 + 4.2i
-2.4 + 6.8i
m⏎
3.0 -1.0⏎
t
3
5 + 3i
9 + 7i
13 - 1i
q
4
5 + 3i
9 + 3i
9 + 7i
5 + 7i
c
2
5 + 3i
9 + 7i
p
5
5 - 1i
7 + 1.2i
-3 - 5.4i
11.6 + 3.2i
0.6 + 5.8i
r⏎
0.99990604980155 0.013707354604752⏎
t
3
4.95841 + 3.06825i
8.9032 + 7.12271i
13.0125 - 0.82171i
q
4
4.95841 + 3.06825i
8.95803 + 3.12308i
8.9032 + 7.12271i
4.90358 + 7.06788i
c
2
4.95841 + 3.06825i
8.9032 + 7.12271i
p
5
5.01324 - 0.931369i
6.98289 + 1.29584i
-2.9257 - 5.44061i
11.555 + 3.3587i
0.520441 + 5.80768i
^Z⏎

Pseudo Code

#include <iostream>
#include <string>
#include <sstream>
#include <cmath>
#include <vector>

using namespace std;

class Geometry_Comp;

class Complex
{
private:
    // data members
    // save the real and imaginary parts of the complex number
    // with `double` precision
    double m_real;
    double m_imag;

public:
    // Constructor, initializes real and imaginary parts
    Complex(const double &arg_real = 0.0, const double &arg_imag = 0.0);
    // Copy constructor
    Complex(const Complex &arg_c);
    // assignment operator
    Complex &operator=(const Complex &arg_c);
    // add assignment operator
    Complex &operator+=(const Complex &arg_c);
    // multiply assignment operator
    Complex &operator*=(const Complex &arg_c);
    // length of the complex number
    double length() const;
    // angle of the complex number in radians
    // use `atan2` to compute the angle by the formula `atan(imag/real)`
    // and use `NAN` for 0/0 case
    // `atan2` ref: https://en.cppreference.com/w/cpp/numeric/math/atan2
    // `NAN` ref: https://en.cppreference.com/w/cpp/numeric/math/NAN
    double angle() const;
    // cout `<<` operator for print complex number
    // note: be careful about the format of output
    friend ostream &operator<<(ostream &arg_os, const Complex &arg_c);
    // cin `>>` operator for input complex number
    // note: use `>>` to parse the string to double,
    // use `istream::fail()` to check the conversion is successful
    // and use `istream::eof()` to check the is parse to the end of line
    friend istream &operator>>(istream &arg_is, Complex &arg_c);
    // friend class
    friend class Geometry_Comp;
};

class Geometry_Comp
{
protected:
    // data members
    vector<Complex> m_comp_array;
    // utility function to check if the transformation is valid
    // hint: use `isnan` to check the angle is valid or not
    // ref: https://en.cppreference.com/w/cpp/numeric/math/isnan
    bool _check_transform(const Complex &arg_trans_c, const char &arg_op);

public:
    // Constructor, initializes the array
    Geometry_Comp(const unsigned int &arg_num_of_vertex = 0);
    // Copy constructor
    Geometry_Comp(const Geometry_Comp &arg_gc);
    // assignment operator
    Geometry_Comp &operator=(const Geometry_Comp &arg_gc);
    // print the geometry
    virtual void print_geometry();
    // parse the cin to the geometry
    virtual void parse_geometry(istream &arg_is);
    // apply transformation to the geometry
    void transform_geometry(const Complex &arg_trans_c, const char &arg_op);
    // set the geometry
    void set_geometry(const vector<Complex> &arg_comp_array);
    // get the geometry array
    vector<Complex> get_geometry_array();
};

class Triangle_Comp : public Geometry_Comp
{
public:
    // Constructor, initializes the array
    Triangle_Comp();
    // Copy constructor
    Triangle_Comp(const Triangle_Comp &arg_tc);
    // assignment operator
    Triangle_Comp &operator=(const Triangle_Comp &arg_tc);
    // print the geometry
    void print_geometry();
    // parse the cin to the geometry
    void parse_geometry(istream &arg_is);
};
const unsigned triangle_num_of_vertex = 3;

class Quadrilateral_Comp : public Geometry_Comp
{
public:
    // Constructor, initializes the array
    Quadrilateral_Comp();
    // Copy constructor
    Quadrilateral_Comp(const Quadrilateral_Comp &arg_qc);
    // assignment operator
    Quadrilateral_Comp &operator=(const Quadrilateral_Comp &arg_qc);
    // print the geometry
    void print_geometry();
    // parse the cin to the geometry
    void parse_geometry(istream &arg_is);
};
const unsigned quadrilateral_num_of_vertex = 4;

class Polygon_Comp : public Geometry_Comp
{
public:
    // Constructor, initializes the array
    Polygon_Comp();
    // Copy constructor
    Polygon_Comp(const Polygon_Comp &arg_pc);
    // assignment operator
    Polygon_Comp &operator=(const Polygon_Comp &arg_pc);
    // print the geometry
    void print_geometry();
    // parse the cin to the geometry
    void parse_geometry(istream &arg_is);
};

class Circle_Comp : public Geometry_Comp
{
public:
    // Constructor, initializes the array
    Circle_Comp();
    // Copy constructor
    Circle_Comp(const Circle_Comp &arg_cc);
    // assignment operator
    Circle_Comp &operator=(const Circle_Comp &arg_cc);
    // print the geometry
    void print_geometry();
    // parse the cin to the geometry
    void parse_geometry(istream &arg_is);
};
const unsigned circle_num_of_vertex = 2;

// error and exit
void error_and_exit()
{
    cout << "Error: Invalid input" << endl;
    exit(1);
}

// used for process the test cases, do not modify
int main()
{
    string input, temp;
    vector<Geometry_Comp *> geo_ptr_array;
    Geometry_Comp *geo_ptr;
    Complex trans_c;
    char trans_op;

    while (getline(cin, input))
    {
        // check the geometry type
        switch (input[0])
        {
        case 't':
            geo_ptr = new Triangle_Comp();
            break;
        case 'q':
            geo_ptr = new Quadrilateral_Comp();
            break;
        case 'p':
            geo_ptr = new Polygon_Comp();
            break;
        case 'c':
            geo_ptr = new Circle_Comp();
            break;
        case 'r':
        case 'z':
        case 'm':
            getline(cin, temp);
            break;
        }
        if (input[0] == 't' || input[0] == 'q' || input[0] == 'p' || input[0] == 'c')
        {
            // parse the cin to the geometry
            geo_ptr->parse_geometry(cin);
            // print the geometry
            geo_ptr->print_geometry();
            // push the pointer to the array
            geo_ptr_array.push_back(geo_ptr);
        }
        else if (input[0] == 'r' || input[0] == 'z' || input[0] == 'm')
        {
            stringstream ss(temp);
            ss >> trans_c;
            // transform the geometry using operator and complex
            for (int i = 0; i < geo_ptr_array.size(); i++)
            {
                geo_ptr_array[i]->transform_geometry(trans_c, input[0]);
                // print transformed geometry
                geo_ptr_array[i]->print_geometry();
            }
        }
    }
    return 0;
}

Reference Code:

TA

#include <iostream>
#include <string>
#include <sstream>
#include <cmath>
#include <vector>

using namespace std;

class Geometry_Comp;

class Complex
{
private:
    // data members
    // save the real and imaginary parts of the complex number
    // with `double` precision
    double m_real;
    double m_imag;

public:
    // Constructor, initializes real and imaginary parts
    Complex(const double &arg_real = 0.0, const double &arg_imag = 0.0);
    // Copy constructor
    Complex(const Complex &arg_c);
    // assignment operator
    Complex &operator=(const Complex &arg_c);
    // add assignment operator
    Complex &operator+=(const Complex &arg_c);
    // multiply assignment operator
    Complex &operator*=(const Complex &arg_c);
    // length of the complex number
    double length() const;
    // angle of the complex number in radians
    double angle() const;
    // cout `<<` operator for print complex number
    // note: be careful about the format of output
    friend ostream &operator<<(ostream &arg_os, const Complex &arg_c);
    // cin `>>` operator for input complex number
    // note: use `>>` to parse the string to double,
    // use `istream::fail()` to check the conversion is successful
    // and use `istream::eof()` to check the is parse to the end of line
    friend istream &operator>>(istream &arg_is, Complex &arg_c);
    // friend class
    friend class Geometry_Comp;
};

class Geometry_Comp
{
protected:
    // data members
    vector<Complex> m_comp_array;
    // utility function to check if the transformation is valid
    bool _check_transform(const Complex &arg_trans_c, const char &arg_op);

public:
    // Constructor, initializes the array
    Geometry_Comp(const unsigned int &arg_num_of_vertex = 0);
    // Copy constructor
    Geometry_Comp(const Geometry_Comp &arg_gc);
    // assignment operator
    Geometry_Comp &operator=(const Geometry_Comp &arg_gc);
    // print the geometry
    virtual void print_geometry();
    // parse the cin to the geometry
    virtual void parse_geometry(istream &arg_is);
    // apply transformation to the geometry
    void transform_geometry(const Complex &arg_trans_c, const char &arg_op);
    // set the geometry
    void set_geometry(const vector<Complex> &arg_comp_array);
    // get the geometry array
    vector<Complex> get_geometry_array();
};

class Triangle_Comp : public Geometry_Comp
{
public:
    // Constructor, initializes the array
    Triangle_Comp();
    // Copy constructor
    Triangle_Comp(const Triangle_Comp &arg_tc);
    // assignment operator
    Triangle_Comp &operator=(const Triangle_Comp &arg_tc);
    // print the geometry
    void print_geometry();
    // parse the cin to the geometry
    void parse_geometry(istream &arg_is);
};
const unsigned triangle_num_of_vertex = 3;

class Quadrilateral_Comp : public Geometry_Comp
{
public:
    // Constructor, initializes the array
    Quadrilateral_Comp();
    // Copy constructor
    Quadrilateral_Comp(const Quadrilateral_Comp &arg_qc);
    // assignment operator
    Quadrilateral_Comp &operator=(const Quadrilateral_Comp &arg_qc);
    // print the geometry
    void print_geometry();
    // parse the cin to the geometry
    void parse_geometry(istream &arg_is);
};
const unsigned quadrilateral_num_of_vertex = 4;

class Polygon_Comp : public Geometry_Comp
{
public:
    // Constructor, initializes the array
    Polygon_Comp();
    // Copy constructor
    Polygon_Comp(const Polygon_Comp &arg_pc);
    // assignment operator
    Polygon_Comp &operator=(const Polygon_Comp &arg_pc);
    // print the geometry
    void print_geometry();
    // parse the cin to the geometry
    void parse_geometry(istream &arg_is);
};

class Circle_Comp : public Geometry_Comp
{
public:
    // Constructor, initializes the array
    Circle_Comp();
    // Copy constructor
    Circle_Comp(const Circle_Comp &arg_cc);
    // assignment operator
    Circle_Comp &operator=(const Circle_Comp &arg_cc);
    // print the geometry
    void print_geometry();
    // parse the cin to the geometry
    void parse_geometry(istream &arg_is);
};
const unsigned circle_num_of_vertex = 2;

// error and exit
void error_and_exit()
{
    cout << "Error: Invalid input" << endl;
    exit(1);
}

// Complex class implementation

// Constructor, initializes real and imaginary parts
// hint: as like as `modify` function in examples
// but use default constructor to implement
Complex::Complex(const double &arg_real, const double &arg_imag)
    : m_real(arg_real), m_imag(arg_imag)
{
}

// Copy constructor
Complex::Complex(const Complex &arg_c)
    : m_real(arg_c.m_real), m_imag(arg_c.m_imag)
{
}

// assignment operator
Complex &Complex::operator=(const Complex &arg_c)
{
    if (this == &arg_c) // self-assignment
        return *this;
    m_real = arg_c.m_real;
    m_imag = arg_c.m_imag;
    return *this;
}

// add assignment operator
Complex &Complex::operator+=(const Complex &arg_c)
{
    m_real += arg_c.m_real;
    m_imag += arg_c.m_imag;
    return *this;
}

// multiply assignment operator
Complex &Complex::operator*=(const Complex &arg_c)
{
    double real = m_real * arg_c.m_real - m_imag * arg_c.m_imag;
    double imag = m_real * arg_c.m_imag + m_imag * arg_c.m_real;
    m_real = real;
    m_imag = imag;
    return *this;
}

// length of the complex number
double Complex::length() const
{
    return sqrt(m_real * m_real + m_imag * m_imag);
}

// angle of the complex number in radians
double Complex::angle() const
{
    if (m_real == 0 && m_imag == 0)
    {
        return NAN;
    }
    return atan2(m_imag, m_real);
}

// cout `<<` operator for print complex number
// note: be careful about the format of output
ostream &operator<<(ostream &arg_os, const Complex &arg_c)
{
    if (arg_c.m_imag > 0)
    {
        arg_os << arg_c.m_real << " + " << arg_c.m_imag << "i";
    }
    else if (arg_c.m_imag < 0)
    {
        arg_os << arg_c.m_real << " - " << -arg_c.m_imag << "i";
    }
    else
    {
        arg_os << arg_c.m_real;
    }
    return arg_os;
}

// cin `>>` operator for input complex number
// note: be careful about the format of input
istream &operator>>(istream &arg_is, Complex &arg_c)
{
    double input_real, input_imag;
    arg_is >> input_real;
    if (arg_is.fail())
    {
        error_and_exit();
    }
    arg_is >> input_imag;
    if (arg_is.fail() || !arg_is.eof())
    {
        error_and_exit();
    }
    arg_c.m_real = input_real;
    arg_c.m_imag = input_imag;
    return arg_is;
}

// Geometry_Comp class implementation

// check if the transformation is valid
bool Geometry_Comp::_check_transform(const Complex &arg_c, const char &arg_op)
{
    // check if the operation is valid
    if (arg_op == 'r' && (arg_c.length() != 1 || isnan(arg_c.angle())))
    {
        return false;
    }
    else if (arg_op == 'z' && (arg_c.m_real == 0 || arg_c.m_imag != 0))
    {
        return false;
    }
    else
    {
        return true;
    }
}
// Constructor, initializes the array
Geometry_Comp::Geometry_Comp(const unsigned int &arg_num_of_vertex)
    : m_comp_array(arg_num_of_vertex)
{
}
// Copy constructor
Geometry_Comp::Geometry_Comp(const Geometry_Comp &arg_gc)
    : m_comp_array(arg_gc.m_comp_array)
{
}
// assignment operator
Geometry_Comp &Geometry_Comp::operator=(const Geometry_Comp &arg_gc)
{
    if (this == &arg_gc) // self-assignment
        return *this;
    m_comp_array = arg_gc.m_comp_array;
    return *this;
}
// print the geometry
void Geometry_Comp::print_geometry()
{
    cout << "not implemented" << endl;
}
// parse the cin to the geometry
void Geometry_Comp::parse_geometry(istream &arg_is)
{
    cout << "not implemented" << endl;
}
// apply transformation to the geometry
void Geometry_Comp::transform_geometry(const Complex &arg_c, const char &arg_op)
{
    if (!(_check_transform(arg_c, arg_op)))
    {
        error_and_exit();
    }
    if (arg_op == 'm')
    {
        for (unsigned int i = 0; i < m_comp_array.size(); i++)
        {
            m_comp_array[i] += arg_c;
        }
    }
    else if (arg_op == 'r' || arg_op == 'z')
    {
        for (unsigned int i = 0; i < m_comp_array.size(); i++)
        {
            m_comp_array[i] *= arg_c;
        }
    }
}
// set the geometry
void Geometry_Comp::set_geometry(const vector<Complex> &arg_comp_array)
{
    m_comp_array = arg_comp_array;
}
// get the geometry array
vector<Complex> Geometry_Comp::get_geometry_array()
{
    return m_comp_array;
}

// Triangle_Comp class implementation

// Constructor, initializes the array
Triangle_Comp::Triangle_Comp()
    : Geometry_Comp(triangle_num_of_vertex)
{
}
// Copy constructor
Triangle_Comp::Triangle_Comp(const Triangle_Comp &arg_tc)
    : Geometry_Comp(arg_tc)
{
}
// assignment operator
Triangle_Comp &Triangle_Comp::operator=(const Triangle_Comp &arg_tc)
{
    if (this == &arg_tc) // self-assignment
        return *this;
    Geometry_Comp::operator=(arg_tc);
    return *this;
}
// print the geometry
void Triangle_Comp::print_geometry()
{
    cout << "t" << endl;
    cout << m_comp_array.size() << endl;
    for (int i = 0; i < triangle_num_of_vertex; i++)
    {
        cout << m_comp_array[i] << endl;
    }
}
// parse the cin to the geometry
void Triangle_Comp::parse_geometry(istream &arg_is)
{
    string temp;
    getline(arg_is, temp); // get the vertex number
    stringstream ss(temp);
    unsigned int vertex_num;
    ss >> vertex_num;
    if (vertex_num != triangle_num_of_vertex)
    {
        error_and_exit();
    }

    for (int i = 0; i < vertex_num; i++)
    {
        getline(arg_is, temp);
        stringstream ss(temp);
        Complex c;
        ss >> c;
        if (ss.fail())
        {
            error_and_exit();
        }
        m_comp_array[i] = c;
    }
}

// Quadrilateral_Comp class implementation

// Constructor, initializes the array
Quadrilateral_Comp::Quadrilateral_Comp()
    : Geometry_Comp(quadrilateral_num_of_vertex)
{
}
// Copy constructor
Quadrilateral_Comp::Quadrilateral_Comp(const Quadrilateral_Comp &arg_qc)
    : Geometry_Comp(arg_qc)
{
}
// assignment operator
Quadrilateral_Comp &Quadrilateral_Comp::operator=(const Quadrilateral_Comp &arg_qc)
{
    if (this == &arg_qc) // self-assignment
        return *this;
    Geometry_Comp::operator=(arg_qc);
    return *this;
}
// print the geometry
void Quadrilateral_Comp::print_geometry()
{
    cout << "q" << endl;
    cout << m_comp_array.size() << endl;
    for (int i = 0; i < quadrilateral_num_of_vertex; i++)
    {
        cout << m_comp_array[i] << endl;
    }
}
// parse the cin to the geometry
void Quadrilateral_Comp::parse_geometry(istream &arg_is)
{
    string temp;
    getline(arg_is, temp); // get the vertex number
    int vertex_num = stoi(temp);
    if (vertex_num != quadrilateral_num_of_vertex)
    {
        error_and_exit();
    }

    for (int i = 0; i < vertex_num; i++)
    {
        getline(arg_is, temp);
        stringstream ss(temp);
        Complex c;
        ss >> c;
        if (ss.fail())
        {
            error_and_exit();
        }
        m_comp_array[i] = c;
    }
}

// Polygon_Comp class implementation

// Constructor, initializes the array
Polygon_Comp::Polygon_Comp()
    : Geometry_Comp()
{
}
// Copy constructor
Polygon_Comp::Polygon_Comp(const Polygon_Comp &arg_pc)
    : Geometry_Comp(arg_pc)
{
}
// assignment operator
Polygon_Comp &Polygon_Comp::operator=(const Polygon_Comp &arg_pc)
{
    if (this == &arg_pc) // self-assignment
        return *this;
    Geometry_Comp::operator=(arg_pc);
    return *this;
}
// print the geometry
void Polygon_Comp::print_geometry()
{
    cout << "p" << endl;
    cout << m_comp_array.size() << endl;
    for (int i = 0; i < m_comp_array.size(); i++)
    {
        cout << m_comp_array[i] << endl;
    }
}
// parse the cin to the geometry
void Polygon_Comp::parse_geometry(istream &arg_is)
{
    string temp;
    getline(arg_is, temp); // get the vertex number
    int vertex_num = stoi(temp);
    if (vertex_num < triangle_num_of_vertex)
    {
        error_and_exit();
    }
    m_comp_array.resize(vertex_num);
    for (int i = 0; i < vertex_num; i++)
    {
        getline(arg_is, temp);
        stringstream ss(temp);
        Complex c;
        ss >> c;
        if (ss.fail())
        {
            error_and_exit();
        }
        m_comp_array[i] = c;
    }
}

// Circle_Comp class implementation

// Constructor, initializes the array
Circle_Comp::Circle_Comp()
    : Geometry_Comp(circle_num_of_vertex)
{
}
// Copy constructor
Circle_Comp::Circle_Comp(const Circle_Comp &arg_cc)
    : Geometry_Comp(arg_cc)
{
}
// assignment operator
Circle_Comp &Circle_Comp::operator=(const Circle_Comp &arg_cc)
{
    if (this == &arg_cc) // self-assignment
        return *this;
    Geometry_Comp::operator=(arg_cc);
    return *this;
}
// print the geometry
void Circle_Comp::print_geometry()
{
    cout << "c" << endl;
    cout << m_comp_array.size() << endl;
    for (int i = 0; i < circle_num_of_vertex; i++)
    {
        cout << m_comp_array[i] << endl;
    }
}
// parse the cin to the geometry
void Circle_Comp::parse_geometry(istream &arg_is)
{
    string temp;
    getline(arg_is, temp); // get the vertex number
    int vertex_num = stoi(temp);
    if (vertex_num != circle_num_of_vertex)
    {
        error_and_exit();
    }

    for (int i = 0; i < vertex_num; i++)
    {
        getline(arg_is, temp);
        stringstream ss(temp);
        Complex c;
        ss >> c;
        if (ss.fail())
        {
            error_and_exit();
        }
        m_comp_array[i] = c;
    }
}

int main()
{
    string input, temp;
    vector<Geometry_Comp *> geo_ptr_array;
    Geometry_Comp *geo_ptr;
    Complex trans_c;
    char trans_op;

    while (getline(cin, input))
    {
        // check the geometry type
        switch (input[0])
        {
        case 't':
            geo_ptr = new Triangle_Comp();
            break;
        case 'q':
            geo_ptr = new Quadrilateral_Comp();
            break;
        case 'p':
            geo_ptr = new Polygon_Comp();
            break;
        case 'c':
            geo_ptr = new Circle_Comp();
            break;
        case 'r':
        case 'z':
        case 'm':
            getline(cin, temp);
            break;
        default:
            for (int i = 0; i < geo_ptr_array.size(); i++)
            {
                delete geo_ptr_array[i];
            }
            error_and_exit();
        }
        if (input[0] == 't' || input[0] == 'q' || input[0] == 'p' || input[0] == 'c')
        {
            // parse the cin to the geometry
            geo_ptr->parse_geometry(cin);
            // print the geometry
            geo_ptr->print_geometry();
            // push the pointer to the array
            geo_ptr_array.push_back(geo_ptr);
        }
        else if (input[0] == 'r' || input[0] == 'z' || input[0] == 'm')
        {
            stringstream ss(temp);
            ss >> trans_c;
            // transform the geometry using operator and complex
            for (int i = 0; i < geo_ptr_array.size(); i++)
            {
                geo_ptr_array[i]->transform_geometry(trans_c, input[0]);
                // print transformed geometry
                geo_ptr_array[i]->print_geometry();
            }
        }
        else
        {
            for (int i = 0; i < geo_ptr_array.size(); i++)
            {
                delete geo_ptr_array[i];
            }
            error_and_exit();
        }
    }
    return 0;
}