zoukankan      html  css  js  c++  java
  • 个人项目

    这个作业属于哪个课程 2020春北航计算机学院软件工程(罗杰 任健)
    这个作业的要求在哪里 个人项目作业
    我在这个课程的目标是 增强软件开发能力,增强沟通表达能力
    这个作业在哪个具体方面帮助我实现目标 完成个人项目,接触软件开发流程
    教学班级   006
    github地址 https://github.com/Therp-GY/IntersectProject

    PSP表格

    PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
    Planning 计划    
    · Estimate · 估计这个任务需要多少时间  10  10
    Development 开发    
    · Analysis · 需求分析 (包括学习新技术)  100  180
    · Design Spec · 生成设计文档 10  10
    · Design Review · 设计复审 (和同事审核设计文档)  5  5
    · Coding Standard · 代码规范 (为目前的开发制定合适的规范)  5  5
    · Design · 具体设计  80  100
    · Coding · 具体编码  120  300
    · Code Review · 代码复审  30  30
    · Test · 测试(自我测试,修改代码,提交修改) 40  60
    Reporting 报告    
    · Test Report · 测试报告  60  100
    · Size Measurement · 计算工作量  10  10
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划  20  20
      合计  490  830

    实际耗时远远大于预估时间。1. 对语言不熟练,导致简单代码也花费了一些时间 2.第一次按照规范流程完成项目,在一个个环节上也不够熟练,问题颇多。

    解题思路

    直线表示方法:ax + by + c = 0

    圆表示方式:(x-a)^2 + (y-b)^2 = r^2

    直线与直线之间求交点直接联立方程求解,然而圆与直线、圆与圆方程求解实现并不简单,于是关于圆交点的求解用几何方法,只需要引入向量类(实际上就是交点类),进行向量加减法即可完成求解。

    圆与直线交点

    圆与圆交点

    关于精度:我使用double类型,因此需要引入eps精度。

    关于重复点:由于时间原因,我使用较为暴力的方法。建立一个交点容器和一个几何对象容器,在每次输入新的几何对象后,求它和几何对象容器中所有几何对象的交点,并将这些交点插入到交点容器中,若容器中已经存在这个交点则不插入。

    设计实现过程

    my_math.h头文件中定义了三个类,点类、线类、圆类

     点类

    class Point {
        double x_;
        double y_;
    public:
        Point(double x, double y);
        Point();
        double get_x()const;
        double get_y()const;
        double distance(const Point& point)const;
        bool operator==(const Point& point) const;
        bool operator<(const Point& point) const;  //  重载用于set容器
        Point operator+(const Point& point) const;
        Point operator-(const Point& point) const;
        Point operator*(const double& d) const;
        Point operator/(const double& d) const;
        friend void operator<<(std::ostream &os,  Point &point);
    };
    
    typedef Point Vector;   //  点类就是向量类

    线类

    class Line {
        double a;
        double b;
        double c;
        //    ax + by + c = 0
    public:
        Line(const Point& p1, const  Point& p2);
        Line(const double& a_, const double& b_, const double& c_);
        Line(const double& a_, const double& b_, const Point &point);
        Point find_intersection(const Line &line);    //  线和线的交点
        double get_a()const;
        double get_b()const;
        double get_c()const;
        Vector get_directionVector()const;  //  单位向量
        bool operator==(const Line& line); 
        friend void operator<<(std::ostream& os, Line& line);
    };

    圆类

    class Circle {
        Point o;
        double r;
    public:
        Circle(const Point& point, const double r_);
        Circle();
        int find_intersection(const Line& line , Point *p);  //  圆和线的交点
        int find_intersection(const Circle& circle, Point* p);  //  圆和圆的交点
        double get_r()const;
        Point get_o()const;
    
    };

    关键函数比较离散,并不复杂。线线、圆线都是独立求的,圆圆会转化为圆线相交,逻辑比较简单。

    单元测试

    对线线测试相交、平行、重合(即报错)情况。通过测试

    对线圆测试相交、相切、相离情况。通过测试

    对圆圆测试内切、外切、相交、无交点情况。通过测试

    并使用GeoGebra进行测试多种几何对象相交情况(未写入单元测试)

     同时每一次版本改变就做回归测试。

    性能改进

    性能改进上花了约120min,由于对c++一些数据结构并没有清晰的概念,导致在改进上速度很慢。

    我最开始选择存储点的容器未map,但是一开始对insert函数的误操作,在insert上又加find函数,导致在查找点时连续进行两次查找,耗时巨大。

    在将find去除后,性能探查器得到如下结果。测试数据为5000组。

    性能消耗最大的函数即find_intersection,因为要遍历所有已有点并完成插入工作。

    void find_intersection_l_l(Line &l,vector<Line> &l_list, set<Point>&p_set) {
        for (unsigned int i = 0; i < l_list.size(); i++) {
            Point p;
            Point nopoint(INFINITY, INFINITY);
            p = l_list[i].find_intersection(l);
            if (p == nopoint)continue;
            p_set.insert(p);
        }
    }

    map效果十分不理想,由此我又使用set存储点,只存储唯一键值。

    以下是用set进行5000组测试。

     可以看出速度变快了许多,性能有很大改进。

    但由于都是有序容器,因此我想尝试无序容器。因此我采用过unordered_set,因为无序查找速度更快。 但并没有很大的效果改进,甚至时间更长了,或许是我的hash函数并没有很好的分配索引,hash查找比起有序查找在性能上没有显著进步。

    代码说明

    线线求交点,直接联立直线方程求解。                                                                        

    Point Line::find_intersection(const Line& line)
    {
        if (*this == line) {
            std::cout << "两条线重合, 无数个交点" << std::endl;
            /*abort();*/
        }
        else {
            if (b * line.a - a * line.b == 0) {
                return Point();
            }
            else {
                double x;
                double y;
                y = (a * line.c - c * line.a) / (b * line.a - a * line.b);
                if (a != 0) {
                    x = (- c - b * y) / a;
                }
                else {
                    x = (-line.c - line.b * y) / line.a;
                }
                return Point(x, y);
            }
        }
    }        

    圆线求交点,算出圆心到直线的距离,再用勾股定理算出弦长并转化为向量,然后求解点。

    int Circle::find_intersection(const Line& line, Point* p)
    {
        int n;    //    交点个数
        Vector line_vector = line.get_directionVector();    //    line 的单位向量
        Line line_h(-line.get_b(), line.get_a(), o); // 和 line 垂直且过圆心的垂线 line_h
        Point i1 = line_h.find_intersection(line);    // l_h 和 line 的交点 i1
        double d = i1.distance(o);    //    i1 到 圆心 o 的 距离
        double l = sqrt(pow(r, 2) - pow(d, 2));    //  sqrt(r^2 - d^2)
        Vector v = line_vector* l;
        *p = i1 + line_vector * l;
        *(p+1) = i1 - line_vector * l;
    
        if (d > r) {
            n = 0;
            return n;
        }
        else if (abs(d - r) <= eps) n = 1;
        else n = 2;
        return n;
    }

                                      

    圆圆求交点,用几何做法比较麻烦,要分别判断是不相交、外切、内切、相交,然后依靠向量求解。

    int Circle::find_intersection(const Circle& circle, Point* p)
    {
        if (o == circle.o && (r - circle.r) < eps) {
            std::cout << "两圆重合,无数个交点" << std::endl;
            /*abort();*/
            return 0;
        }
    
        //    交点个数
        int n;
    
        //    分大小圆
        Circle big;
        Circle small;
        if (r >= circle.r) {
            big = *this;
            small = circle;
        }
        else {
            big = circle;
            small = *this;
        }
    
        //    判断交点个数
        double d = big.o.distance(small.o);
        if (d > (big.r + small.r) || d < big.r - small.r) {
            n = 0;
            return n;
        }
        else if (abs(d - (big.r + small.r)) <= eps) {    //    小圆外切
            n = 1;
            Vector v1 = small.o - big.o;    //    大圆圆心射向小圆圆心的向量
            v1 = v1 * (big.r / (big.r + small.r));
            *p = big.o + v1;
            return n;
        }
        else if (abs(d - (big.r - small.r)) <= eps) {    //    小圆内切
            n = 1;
            Vector v1 = small.o - big.o;    //    大圆圆心射向小圆圆心的向量
            v1 = v1 / big.o.distance(small.o) * big.r;
            *p = big.o + v1;
            return n;
        }
        else  {    // 2个交点  d ,r1,r2形成三角形 
            n = 2;
            Vector v1 = small.o - big.o;
            v1 = v1 / big.o.distance(small.o);    //    单位向量
            double x = (pow(big.r, 2) - pow(small.r, 2) + pow(d, 2)) / (2 * d);
            v1 = v1 *  x;
            Point cross = big.o + v1;
            Line l(v1.get_x(), v1.get_y(), cross);
            big.find_intersection(l, p);
            return n;
        }
        return 0;
    }

    是否有运行警告

  • 相关阅读:
    SAS学习笔记38 SAS Comments注释语句
    SAS学习笔记37 宏程序中parmbuff选项
    SAS学习笔记36 二分类logistic回归
    SAS学习笔记34 指针控制
    SAS学习笔记33 格式修饰符
    SAS学习笔记31 SAS随机分组方法及实现
    angular的websocket使用
    angularjs 使用ui.router 去掉url中的#号
    angular全局确认框confirm
    angular 请求$http载入画面Loading
  • 原文地址:https://www.cnblogs.com/Therp-GY/p/12452984.html
Copyright © 2011-2022 走看看