Lab 14: File Export of Complex Number's Geometry
Lab 14-1: Simple Complex Number Geometry Transformation (Text File ver.) (75%)
- 輸入:
- 從檔案中讀取多個幾何形狀或幾何變換的複數資料。
- 請使用
int main(int argc, char *argv[])
來開啟指定檔案 (Ref: One and the only: main function。 - 開啟檔案名稱會放在
argv[1]
中。
- 請使用
- 幾何圖形
- 以
char
格式讀取幾何圖形形狀,包含三角形 (t
)、四邊形 (q
)、多邊形 (p
)、圓形 (c
),一行讀取一個幾何圖形 - 以
unsinged int
格式讀取幾何圖形的頂點數,一行讀取一個正整數- 三角形:3
- 四邊形:4
- 多邊形:大於 3 的正整數
- 圓形:2
- 以
double
格式讀取組合幾何圖形的複數的實數及虛數部分,以空格分開,一行讀取一個複數 - 讀取幾何圖形形狀及頂點數後依據 2. 的頂點數接著讀取相對應的複數
- 三角形:連續讀取三個複數
- 四邊形:連續讀取四個複數
- 多邊形:連續讀取多個複數
- 圓形:連續讀取兩個複數
- 幾何變換
- 以
char
格式讀取幾何變換字元,包含以0
點旋轉 (r
)、以0
點縮放 (z
)、平移 (m
),一行讀取一個幾何變換 - 以
double
格式讀取幾何變換的複數的實數及虛數部分,以空格分開,一行讀取一個複數- 以
0
點旋轉:\(z * (cos(\theta) + sin(\theta)i), norm = 1\) - 以
0
點縮放:\(z * (r + 0i)\) - 平移:\(z + (x + yi)\)
- 以
- 讀取幾何變換後須將所有的幾何圖形複數變換
- 從檔案中讀取多個幾何形狀或幾何變換的複數資料。
- 輸出:
- 將結果的幾何形狀及幾何變換的複數資料輸出至指令列及檔案中。
- 請使用
int main(int argc, char *argv[])
來開啟指定檔案 (Ref: One and the only: main function。 - 開啟檔案名稱會放在
argv[2]
中。
- 請使用
- 幾何圖形
- 顯示紀錄幾何圖形的形狀、頂點個數及其複數
- 格式請參考 Format 中的說明
- 頂點順序與讀取順序相同
- 複數的格式為
(-)<real result> (+|-) (<imag result>i)
- 若虛數部分為 0 則僅顯示實數部分
- 若虛數部分小於 0 則中間的
+
要改成-
,並且虛數部分要顯示絕對值
- 虛數及實數部分皆以預設
double
格式顯示
- 顯示紀錄幾何圖形的形狀、頂點個數及其複數
- 幾何變換
- 輸出變換後的所有幾何圖形複數
- 將結果的幾何形狀及幾何變換的複數資料輸出至指令列及檔案中。
- 檔名:
lab14-1_<學號>.cpp
(e.g.lab14-1_106062802.cpp
)
注意事項:
- 程式不會輸出任何使用者提示,只會輸出程式結果
- 使用者不需要處理錯誤輸入
- 請基於 pseudo code 提供的
main
及print_output_file
進行修改來處理輸入與輸出 - 程式需要於 10 秒內完成,所有的測資皆會保證於 10 秒內完成
Input Format
Geometry Objects
<geometry type>⏎
n⏎
<real 1> <imag 1>⏎
<real 2> <imag 2>⏎
...
<real n> <imag n>⏎
<EOF>
Transformation
<geometry type 1>⏎
n⏎
<real 1> <imag 1>⏎
<real 2> <imag 2>⏎
...
<real n> <imag n>⏎
<geometry type 2>⏎
n⏎
<real 1> <imag 1>⏎
<real 2> <imag 2>⏎
...
<real n> <imag n>⏎
<geometry transformation type>⏎
(-)<real trans> (+|-) (<imag trans>i)⏎
<EOF>
Output Format
Geometry Objects
<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>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)
<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)
...
Example
Geometry Objects
Triangle
Input File: input_triangle.txt
t
3
1.0 2.0
3.0 4.0
5.0 0.0
Output File: output_triangle.txt
t
3
1 + 2i
3 + 4i
5
Terminal:
$ ./a.out input_triangle.txt output_triangle.txt
t
3
1 + 2i
3 + 4i
5
$
Quadrilateral
Input File: input_quadrilateral.txt
q
4
1.0 2.0
3.0 2.0
3.0 4.0
1.0 4.0
Output File: output_quadrilateral.txt
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
Terminal:
$ ./a.out input_quadrilateral.txt output_quadrilateral.txt
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
$
Circle
Input File: input_circle.txt
c
2
1.0 2.0
3.0 4.0
Output File: output_circle.txt
c
2
1 + 2i
3 + 4i
Terminal:
$ ./a.out input_circle.txt output_circle.txt
c
2
1 + 2i
3 + 4i
$
Polygon
Input File: input_polygon.txt
p
5
1.0 0.0
2.0 1.1
-3.0 -2.2
4.3 2.1
-1.2 3.4
Output File: output_polygon.txt
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
Terminal:
$ ./a.out input_polygon.txt output_polygon.txt
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
$
Multiple Objects
Input File: input_multiple_objects.txt
t
3
1.0 2.0
3.0 4.0
5.0 0.0
q
4
1.0 2.0
3.0 2.0
3.0 4.0
1.0 4.0
c
2
1.0 2.0
3.0 4.0
p
5
1.0 0.0
2.0 1.1
-3.0 -2.2
4.3 2.1
-1.2 3.4
Output File: output_multiple_objects.txt
t
3
1 + 2i
3 + 4i
5
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
c
2
1 + 2i
3 + 4i
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
Terminal:
$ ./a.out input_multiple.txt output_multiple.txt
t
3
1 + 2i
3 + 4i
5
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
c
2
1 + 2i
3 + 4i
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
$
Transformation
Scaling
Input File: input_scaling.txt
t
3
1.0 2.0
3.0 4.0
5.0 0.0
z
2.0 0.0
Output File: output_scaling.txt
t
3
1 + 2i
3 + 4i
5
t
3
2 + 4i
6 + 8i
10
Terminal:
$ ./a.out input_scaling.txt output_scaling.txt
t
3
1 + 2i
3 + 4i
5
t
3
2 + 4i
6 + 8i
10
$
Translation
Input File: input_translation.txt
q
4
1.0 2.0
3.0 2.0
3.0 4.0
1.0 4.0
m
3.0 -1.0
Output File: output_translation.txt
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
q
4
4 + 1i
6 + 1i
6 + 3i
4 + 3i
Terminal:
$ ./a.out input_translation.txt output_translation.txt
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
q
4
4 + 1i
6 + 1i
6 + 3i
4 + 3i
$
Rotation
Input File: input_rotation.txt
c
2
1.0 2.0
3.0 4.0
r
0.99990604980155 0.013707354604752
Output File: output_rotation.txt
c
2
1 + 2i
3 + 4i
c
2
0.972491 + 2.01352i
2.94489 + 4.04075i
Terminal:
$ ./a.out input_rotation.txt output_rotation.txt
c
2
1 + 2i
3 + 4i
c
2
0.972491 + 2.01352i
2.94489 + 4.04075i
$
Multiple Transformations
Input File: input_multiple_transformations.txt
p
5
1.0 0.0
2.0 1.1
-3.0 -2.2
4.3 2.1
-1.2 3.4
z
2.0 0.0
m
3.0 -1.0
r
0.99990604980155 0.013707354604752
Output File: output_multiple_transformations.txt
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
p
5
2
4 + 2.2i
-6 - 4.4i
8.6 + 4.2i
-2.4 + 6.8i
p
5
5 - 1i
7 + 1.2i
-3 - 5.4i
11.6 + 3.2i
0.6 + 5.8i
p
5
5.01324 - 0.931369i
6.98289 + 1.29584i
-2.9257 - 5.44061i
11.555 + 3.3587i
0.520441 + 5.80768i
Terminal:
$ ./a.out input_multiple_transformations.txt output_multiple_transformations.txt
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
p
5
2
4 + 2.2i
-6 - 4.4i
8.6 + 4.2i
-2.4 + 6.8i
p
5
5 - 1i
7 + 1.2i
-3 - 5.4i
11.6 + 3.2i
0.6 + 5.8i
p
5
5.01324 - 0.931369i
6.98289 + 1.29584i
-2.9257 - 5.44061i
11.555 + 3.3587i
0.520441 + 5.80768i
$
Multiple Transformations on Multiple Objects
Input File: input_mix.txt
t
3
1.0 2.0
3.0 4.0
5.0 0.0
q
4
1.0 2.0
3.0 2.0
3.0 4.0
1.0 4.0
c
2
1.0 2.0
3.0 4.0
p
5
1.0 0.0
2.0 1.1
-3.0 -2.2
4.3 2.1
-1.2 3.4
z
2.0 0.0
m
3.0 -1.0
r
0.99990604980155 0.013707354604752
Output File: output_mix.txt
t
3
1 + 2i
3 + 4i
5
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
c
2
1 + 2i
3 + 4i
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
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
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
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
Terminal:
$ ./a.out input_mix.txt output_mix.txt
t
3
1 + 2i
3 + 4i
5
q
4
1 + 2i
3 + 2i
3 + 4i
1 + 4i
c
2
1 + 2i
3 + 4i
p
5
1
2 + 1.1i
-3 - 2.2i
4.3 + 2.1i
-1.2 + 3.4i
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
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
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
$
Pseudo Code
#include <iostream>
#include <fstream>
#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(ofstream &arg_ofs);
// parse the cin to the geometry
virtual void parse_geometry(ifstream &arg_ifs);
// 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(ofstream &arg_ofs);
// parse the cin to the geometry
void parse_geometry(ifstream &arg_ifs);
};
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(ofstream &arg_ofs);
// parse the cin to the geometry
void parse_geometry(ifstream &arg_ifs);
};
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(ofstream &arg_ofs);
// parse the cin to the geometry
void parse_geometry(ifstream &arg_ifs);
};
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(ofstream &arg_ofs);
// parse the cin to the geometry
void parse_geometry(ifstream &arg_ifs);
};
const unsigned circle_num_of_vertex = 2;
// error and exit
void error_and_exit()
{
cout << "Error: Invalid input" << endl;
exit(1);
}
void print_output_file(int argc, char *argv[])
{
ifstream ans_ifs(argv[2]);
if (!ans_ifs)
{
cout << "Error: Cannot open output file" << endl;
exit(1);
}
string ans_line;
while (getline(ans_ifs, ans_line))
{
cout << ans_line << endl;
}
ans_ifs.close();
}
int main(int argc, char *argv[])
{
string input, temp;
vector<Geometry_Comp *> geo_ptr_array;
Geometry_Comp *geo_ptr;
Complex trans_c;
char trans_op;
// open & check input file
// open & check output file
while (getline(infile, 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(infile, 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(infile);
// print the geometry
geo_ptr->print_geometry(outfile);
// 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(outfile);
}
}
else
{
for (int i = 0; i < geo_ptr_array.size(); i++)
{
delete geo_ptr_array[i];
}
error_and_exit();
}
}
for (int i = 0; i < geo_ptr_array.size(); i++)
{
delete geo_ptr_array[i];
}
// close input and output file
print_output_file(argc, argv);
return 0;
}
Reference Code:
TA
#include <iostream>
#include <fstream>
#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(ofstream &arg_ofs);
// parse the cin to the geometry
virtual void parse_geometry(ifstream &arg_ifs);
// 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(ofstream &arg_ofs);
// parse the cin to the geometry
void parse_geometry(ifstream &arg_ifs);
};
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(ofstream &arg_ofs);
// parse the cin to the geometry
void parse_geometry(ifstream &arg_ifs);
};
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(ofstream &arg_ofs);
// parse the cin to the geometry
void parse_geometry(ifstream &arg_ifs);
};
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(ofstream &arg_ofs);
// parse the cin to the geometry
void parse_geometry(ifstream &arg_ifs);
};
const unsigned circle_num_of_vertex = 2;
// error and exit
void error_and_exit()
{
cout << "Error: Invalid input" << endl;
exit(1);
}
void print_output_file(int argc, char *argv[])
{
ifstream ans_ifs(argv[2]);
if (!ans_ifs)
{
cout << "Error: Cannot open output file" << endl;
exit(1);
}
string ans_line;
while (getline(ans_ifs, ans_line))
{
cout << ans_line << endl;
}
ans_ifs.close();
}
// 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(ofstream &arg_ofs)
{
cout << "not implemented" << endl;
}
// parse the cin to the geometry
void Geometry_Comp::parse_geometry(ifstream &arg_ifs)
{
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(ofstream &arg_ofs)
{
arg_ofs << "t" << endl;
arg_ofs << m_comp_array.size() << endl;
for (int i = 0; i < triangle_num_of_vertex; i++)
{
arg_ofs << m_comp_array[i] << endl;
}
}
// parse the cin to the geometry
void Triangle_Comp::parse_geometry(ifstream &arg_ifs)
{
string temp;
getline(arg_ifs, 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_ifs, 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(ofstream &arg_ofs)
{
arg_ofs << "q" << endl;
arg_ofs << m_comp_array.size() << endl;
for (int i = 0; i < quadrilateral_num_of_vertex; i++)
{
arg_ofs << m_comp_array[i] << endl;
}
}
// parse the cin to the geometry
void Quadrilateral_Comp::parse_geometry(ifstream &arg_ifs)
{
string temp;
getline(arg_ifs, 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_ifs, 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(ofstream &arg_ofs)
{
arg_ofs << "p" << endl;
arg_ofs << m_comp_array.size() << endl;
for (int i = 0; i < m_comp_array.size(); i++)
{
arg_ofs << m_comp_array[i] << endl;
}
}
// parse the cin to the geometry
void Polygon_Comp::parse_geometry(ifstream &arg_ifs)
{
string temp;
getline(arg_ifs, 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_ifs, 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(ofstream &arg_ofs)
{
arg_ofs << "c" << endl;
arg_ofs << m_comp_array.size() << endl;
for (int i = 0; i < circle_num_of_vertex; i++)
{
arg_ofs << m_comp_array[i] << endl;
}
}
// parse the cin to the geometry
void Circle_Comp::parse_geometry(ifstream &arg_ifs)
{
string temp;
getline(arg_ifs, 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_ifs, temp);
stringstream ss(temp);
Complex c;
ss >> c;
if (ss.fail())
{
error_and_exit();
}
m_comp_array[i] = c;
}
}
int main(int argc, char *argv[])
{
string input, temp;
vector<Geometry_Comp *> geo_ptr_array;
Geometry_Comp *geo_ptr;
Complex trans_c;
char trans_op;
string input_file_path(argv[1]);
string output_file_path(argv[2]);
ifstream infile(input_file_path, ios::in);
if (!infile)
{
cout << "Input file cannot open." << endl;
return -1;
}
ofstream outfile(output_file_path, ios::out | ios::trunc);
if (!outfile)
{
cout << "Output file cannot open." << endl;
return -1;
}
while (getline(infile, 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(infile, 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(infile);
// print the geometry
geo_ptr->print_geometry(outfile);
// 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(outfile);
}
}
else
{
for (int i = 0; i < geo_ptr_array.size(); i++)
{
delete geo_ptr_array[i];
}
error_and_exit();
}
}
for (int i = 0; i < geo_ptr_array.size(); i++)
{
delete geo_ptr_array[i];
}
infile.close();
outfile.close();
print_output_file(argc, argv);
return 0;
}