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)那么直接进入如何判断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.错误总结
(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; }
/* 作者: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 }
#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
原文:https://www.cnblogs.com/guanjinquan/p/14585221.html