C++ Rectangle類的實現


C++:Rectangle---一個經典練習題

1.實現項目Rectangle :main.cpp 、Rectangle.cpp 、 Rectangle.h

  首先我們需要表示出Rectangle的四個角【即四個x,y坐標】

  這一步我們可以使用pair<double,double>實現,也可以自己寫一個Point類

  為了方便,我使用pair

 

2.實現功能:

 (1)計算length 、 width 、 area 

 (2)判斷是不是square、rectangle

 (3)打印圖像

 (4)旋轉圖像

 (5)放縮圖像

 

3.實現步驟分析:

 (1)計算長+寬+面積: 步驟簡單,略過

 (2)判斷是不是square、rectangle

那么直接進入如何判斷rectangle

  條件一:一個矩形,它的對角線必然相等

  條件二:一個矩形,它的對邊相等

  條件三:它不能是一條線

bool MyRectangle::Rectangle::isRectangle( ) const
{
    // 判斷對角線是否相等 and 對邊是否相等
    bool ans = distance(point[0],point[3]) == distance(point[1],point[2]);
    ans &= distance(point[2],point[0]) == distance(point[3],point[1]);
    ans &= distance(point[2],point[3]) == distance(point[1],point[0]);
    for(int i = 0;i < 3;i++){//判斷是不是有重合點
        if(point[i].fi==point[i+1].fi&&point[i].se==point[i+1].se)
            return false;
    }
    return ans;
}

 判斷正方形直接加上鄰邊相等條件即可!

 (3)打印圖像

  首先想到,打印循環的點都是int類型的,但是矩形是double類型的,那么必然會導致顯示不完全的情況,在此說明了。

  對於一個雙重for循環打印,我們考慮對於每一個{i,j}賦予一個屬性:在/不在 矩形內部

  所以我寫了一個inRectangle的判斷函數,這個判斷函數也是很好寫的。

  【詳見https://blog.csdn.net/dapengbusi/article/details/50516126

  就是利用向量的叉乘判斷一個點是不是在舉行外部【特判四個角的情況】

bool MyRectangle::Rectangle::inRectangle(float x,float y) const
{
    const double eps = 0.3; // 這個精度控制真的難受。。。。
    for(PFF it:point){
        if(fabs(x-it.fi) < eps && fabs(y-it.se) < 1e-4)
            return true;
    }
    PFF p = make_pair(x,y);
    for(int i = 0;i < 4;i++)
    {
        if( cross(point[i+1]-point[i],p-point[i]) > eps )
        return false;
    }
    return true;
}

 (4)旋轉嘛,也很簡單,就是一個旋轉公式。

  【詳細請見https://blog.csdn.net/qq_36797743/article/details/85680195

void MyRectangle::Rectangle::rotateRectangle(float deg)
{
    vector<PFF>temp;
    for(PFF&it:point){
        //旋轉公式
        float y = ( (it.se-o.se)*cos(deg) + (it.fi-o.fi)*sin(deg) ) + o.se;
        float x = ( (it.fi-o.fi)*cos(deg) - (it.se-o.se)*sin(deg) ) + o.fi;
        if(x < 0 || x > 25 || y < 0 || y >25){
            cerr<<"旋轉失敗"<<endl;
            return ;
        }
        temp.push_back(make_pair(x,y));
    }
    point.clear();
    point = temp;
}

 (5)放縮,添加一個比例變量,但是很難做到定點放縮【暫且不談了吧】

 

 

4. 總結:

由於這個是黑框程序,所以只能使用字符 '.' 代替實心的矩形,如果使用其它的圖形庫: ege , esayX ,MFC的gdiplus等來編寫,當然也可以基於QT寫一個,語法也是C++的。

 

5.錯誤反省:

 (1)實現過程中發現光標很煩人地閃來閃去。於是加了一段代碼隱藏光標,但是windows.h頭文件與Rectangle類是沖突的,那么我們怎么辦呢?

  為Rectangle加一個命名空間即可,但是這樣的話,在命名空間外部定義的函數,也需要加上一個MyRectangle::作用域符號,然后創建對象時也需要加一個MyRectangle::

 (2)極角排序還需要加強練習啊!

 

文件:

#include <iostream>
#include <windows.h>
#include "Rectangle.h"
using namespace std;

#define mp make_pair

int main()
{
    //隱藏光標
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); // 得到控制台的句柄
    CONSOLE_CURSOR_INFO CursorInfo;                  // 建立光標對象
    GetConsoleCursorInfo(handle,&CursorInfo);        // 得到光標對象的信息
    CursorInfo.bVisible = false;                     // 設置bvisible為 false
    SetConsoleCursorInfo(handle,&CursorInfo);        // 然后設置即可!

    //Rectangle r({1,1},{15,1},{1,15},{14,14});
    //最后一個點錯誤,不能形成矩形
    const float pi = acos(-1);

    //隱藏光標之后,發現windows與Rectangle類起沖突
    //只能使用命名空間解決問題了【代碼量加大。。】

    MyRectangle::Rectangle R(mp(1,1),mp(10,1),mp(1,15),mp(10,15));
    R.print();
    R.rotateRectangle();
    system("pause");
    R.print();

    for(int i = 1;i < 10;i++)
    {
        R.rotateRectangle();
        R.print();
    }


    const double deg = 45.0/180.0*pi;//轉45°,轉換成rad單位,效果最好


    R.setRectangle(mp(10,10),mp(15,10),mp(10,11),mp(15,11));
    R.print();
    R.rotateRectangle();
    system("pause");
    R.print();
    for(int i = 1;i < 10;i++)
    {
        R.rotateRectangle(deg);
        R.print();
    }

    //斜着的
    R.setRectangle(mp(1,3),mp(3,1),mp(4,2),mp(2,4));
    R.print();



    //角度不宜太小,否則可能顯示同一個圖形 / 或者圖像顯示不全
    for(int i = 1;i < 10;i++)
    {
        R.rotateRectangle(deg);
        R.print();
    }

    return 0;
}
main.cpp
/*
 作者:Pigeon
 時間:2021
 功能:作業
 實現方法:寫 C++
 */

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <stdexcept>
using namespace std;
#include "Rectangle.h"

typedef pair<float,float> PFF;
#define fi first
#define se second
// the pre definition

//三個輔助函數
float distance(PFF a,PFF b)
{
    float dx = a.fi - b.fi;
    float dy = a.se - b.se;
    return sqrt(dx*dx+dy*dy);
}

//為了方便,寫一個pair<float,float>中的operator-運算符
PFF operator-(PFF a,PFF b)
{
    return {a.fi-b.fi,a.se-b.se};
}

float cross(PFF a,PFF b)//傳入兩個向量
{
    return ( b.se * a.fi ) - ( a.se * b.fi );
}

MyRectangle::Rectangle::Rectangle(PFF a,PFF b,PFF c,PFF d):rectChar('.'),borderChar('#')
{
    setRectangle(a,b,c,d);
    //ctor
}

void MyRectangle::Rectangle::setRectangle(PFF a,PFF b,PFF c,PFF d)
{
    point.clear();// 必須要清空之前的點
    point.push_back(a);
    point.push_back(b);
    point.push_back(c);
    point.push_back(d);
    sort(point.begin(),point.end());

    //判斷是不是在 0~20內
    const float eps = 1e-9;//精度損失
    for(PFF it:point){
        if(it.fi > 20 || it.fi < eps)
            throw invalid_argument(" invalid x coordinate , x must be 0~20 !");
        if(it.se > 20 || it.se < eps)
            throw invalid_argument(" invalid y coordinate , y must be 0~20 !");
    }
    if(this->isRectangle() == 0){
        throw invalid_argument(" invalid x,y coordinate , can't make a rectangle!");
    }

    //確認是一個矩形,完成后續初始化
    //對角線中心
    o = make_pair((point[0].fi+point[3].fi)/2,(point[0].se+point[3].se)/2);
    //冒泡排序進行極角排序

    for(int i = 0;i < 4;i++)
    {
        for(int j = i;j+1 < 4;j++)
        {
            if(cross(point[j]-o,point[j+1]-o) > 0)
            swap(point[j],point[j+1]);
        }
    }
    point.push_back(point[0]);

    //初始化寬 、 長
    width = min(distance(point[0],point[1]),distance(point[1],point[3]));
    length = max(distance(point[0],point[1]),distance(point[1],point[3]));
}

bool MyRectangle::Rectangle::isRectangle( ) const
{
    // 判斷對角線是否相等 and 對邊是否相等
    bool ans = distance(point[0],point[3]) == distance(point[1],point[2]);
    ans &= distance(point[2],point[0]) == distance(point[3],point[1]);
    ans &= distance(point[2],point[3]) == distance(point[1],point[0]);
    for(int i = 0;i < 3;i++){
        if(point[i].fi==point[i+1].fi&&point[i].se==point[i+1].se)
            return false;
    }
    return ans;
}

bool MyRectangle::Rectangle::isSquare( ) const
{
    if( isRectangle( ) && getWidth() == getLength() )//是矩形而且邊長相等
        return true;
    return false;
}

float MyRectangle::Rectangle::getWidth( ) const // 短軸距離
{
     return width;
}

float MyRectangle::Rectangle::getLength( ) const // 長軸距離
{
    return length;
}

float MyRectangle::Rectangle::getArea( ) const
{
    return getLength()*getWidth();
}

void MyRectangle::Rectangle::setFillCharacter( const char&ch )
{
    rectChar = ch;
}

void MyRectangle::Rectangle::setPerimeterCharacter( const char&ch )
{
    borderChar = ch;
}

bool MyRectangle::Rectangle::inRectangle(float x,float y) const
{
    const double eps = 0.3; // 這個精度控制真的難受。。。。
    for(PFF it:point){
        if(fabs(x-it.fi) < eps && fabs(y-it.se) < 1e-4)
            return true;
    }
    PFF p = make_pair(x,y);
    for(int i = 0;i < 4;i++)
    {
        if( cross(point[i+1]-point[i],p-point[i]) > eps )
        return false;
    }
    return true;
}

bool MyRectangle::Rectangle::onBorder(float x,float y)const
{
    const float eps = 1e-7;
    return( fabs(x) < eps ||
            fabs(y) < eps ||
            fabs(y-25) < eps ||
            fabs(x-25) < eps );
}

void MyRectangle::Rectangle::print( ) const
{
    system("cls");
    for(int i = 0;i <= 25;i++)
    {
        for(int j = 0;j <= 25;j++)
        {
            if(onBorder(i,j))cout<<borderChar<<" ";
            else if(inRectangle(i,j))cout<<rectChar<<" ";
            else cout<<"  ";
        }
        cout<<endl;
    }
}

void MyRectangle::Rectangle::rotateRectangle(float deg)
{
    vector<PFF>temp;
    for(PFF&it:point){
        //旋轉公式
        float y = ( (it.se-o.se)*cos(deg) + (it.fi-o.fi)*sin(deg) ) + o.se;
        float x = ( (it.fi-o.fi)*cos(deg) - (it.se-o.se)*sin(deg) ) + o.fi;
        if(x < 0 || x > 25 || y < 0 || y >25){
            cerr<<"旋轉失敗"<<endl;
            return ;
        }
        temp.push_back(make_pair(x,y));
    }
    point.clear();
    point = temp;
}

MyRectangle::Rectangle::~Rectangle()
{
    //dtor
}
Rectangle.cpp
#ifndef RECTANGLE_H
#define RECTANGLE_H

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

namespace MyRectangle
{
typedef pair<float,float> PFF;

class Rectangle
{
public:
    Rectangle(
        PFF L1 = {1,1},PFF L2 = {1,20},
        PFF R1 = {20,1}, PFF R2 = {20,20}
    );
    virtual ~Rectangle( );

    //check function
    bool isRectangle( ) const;
    bool isSquare( ) const;
    bool inRectangle(float, float) const;//檢驗這個點在不在矩形內
    bool onBorder(float, float) const;  //檢驗這個點是不是邊界

    //get function
    float getWidth( ) const;
    float getLength( ) const;
    float getArea( ) const;

    //set Function
    void setRectangle(PFF,PFF,PFF,PFF);
    void setFillCharacter(const char&);
    void setPerimeterCharacter(const char&);

    //print function
    void print( ) const;

    //加分函數
    void rotateRectangle(float = 1.570796326794896619);//默認旋轉: pi/2
    /*
    *   支持旋轉一定角度
    *   默認 “定點” 為對角線交點
    *   確定旋轉的 “定點”
    *   先檢驗轉換之后 矩形是否合法 再進行旋轉
    *   所有點根據 “定點” 來旋轉
    */


private:
    vector<PFF> point;
    PFF o;// 對角線交點
    float width , length;
    char rectChar , borderChar;
};

}

#endif // RECTANGLE_H
Rectangle.h

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM