Individual project operations $ \ cdot $ seek the number of intersection

Individual project work \ (\ cdot \) seeking the number of intersection

I. Introduction to operational requirements

The job is a personal project work in software engineering courses Northern College of Computer, Personal development capabilities for software development teams is critical, this project aims to enable students to learn techniques commonly used by individual developers seeking a geometry of the intersection of demand such as PSP method, requirements analysis, design documentation, coding, implementation, testing, performance evaluation and so on.

project content
This work belongs to the Northern software engineering courses Park class blog blog
Please click on the link to see the job requirements Individual project work
Class: 006 Sample
GitHub address IntersectProject
My goal of this course is Ability to obtain as a software engineer
In particular aspects of the job which helped me achieve goals Summing up the past, planning for the future

Two, PSP form

PSP2.1 Personal Software Process Stages Estimated time consuming (minutes) The actual time-consuming (minutes)
Planning plan 90 83
· Estimate • Estimate how much time this task requires 90 83
Development Develop 830 1320
· Analysis · Needs analysis (including learning new technologies) 30 60
· Design Spec Generate design documents 60 40
· Design Review · Design Review (and his colleagues reviewed the design documents) 60 60
· Coding Standard · Code specifications (development of appropriate norms for the current development) 20 20
· Design · Specific design 60 120
· Coding · Specific coding 240 480
· Code Review · Code Review 0 0
· Test · Test (self-test, modify the code, submit modifications) 360 540
Reporting report 180 240
· Test Report · testing report 30 180
· Size Measurement · Computing workload 30 30
· Postmortem & Process Improvement Plan · Hindsight, and propose process improvement plan 120 30
total 1100 1560

Third, the problem-solving ideas description

Topic demand brief

  • Title needs, given straight lines, find the number of the intersection
  • The number of straight line1000 <= N <= 500000
  • The number of intersection0 <= h <= 5000000
  • A long time running 60s

Problem-solving ideas

To get the title first thought violence solved, between two calculate the intersection, then go heavy. But this is pure \ (O (n ^ 2) \) complexity, necessarily the TLE. Thought to want to change it did not expect the worst on the complexity of nature (O (n ^ 2) \ ) \ algorithm. So they checked online some information and found that the Internet has an important topic limited, three-wire common point does not exist. But we demand this subject is to allow a total of three-wire point, it did not help.

After seeing the number of intersections 0 <= h <= 5000000of limitation, perhaps worst feeling complexity \ (O (n ^ 2) \) algorithm solution is not impossible, because if there are N = 500000straight lines do not exist three common point line and parallel to it, does there \ (N (N-1) / 2 \) intersections, but the reason why the number of intersections is limited h <= 5000000, it shows a large number of multi-line concurrent and parallel .

Want to continue along this line of thought, we can in violence \ (O (n ^ 2) \) consider algorithm based on the multi-line concurrent and parallel situation pruned, the complexity of the specific time after the pruning is more complex I did not calculate, but it should be time to meet the conditions, the paper will be subjected to stress tests.

Fourth, the design documents

(一)PipeLine

PreProcess

  • ReadShape : reading the input file receiving all linear and circular
  • Construct the Shape : the shape of the object based on the input construct, the slope is calculated.
  • Slope by Classified : the slope of the linear press packet saved.

CalcIntersect

  • CalcLines : calculate the intersection between all the lines:
    • Sequentially considering each of the parallel group, each line traversed by computing the intersection. Parallel lines in the group without calculation intersection.
    • Check the intersection table, if present, can not seek other lines of the same intersection.
      Table intersection: Map <points, Set <line>>
      Maintenance intersection table: Add new intersection intersection table, line join line set table a corresponding
  • CalcCircles : count after all the lines, and then round one traversal. Finding all violence before its intersection with the graphics.
  • When calculating the intersection point of the straight line and the circle, pruning can be as follows:
    Consider the circle of intersection with a family of parallel lines, parallel lines would intercept sort of group B1, B2, B3 \ (\ cdots \)
    if the start of bi CIRCULAR from, i is greater than a certain phase from the line, anyway, it is smaller than vice versa.

(Ii) between the UML class diagram

  • CIntersect categories : implement control flow, the method comprising an input , calculates the intersection point of the two patterns , calculating the total number of intersection
  • CShape categories : Graphic base class, create a unique id for each graphic instance
  • CLine CCircle classes and categories : base class inheritance pattern, act as parameters showing the shape of algebraic equations.
  • Two representations linear equation
    • General equation: \ (Ax of + By + C = 0 \)
    • Truncated equation: \ (Y = KX + B \)
    • On both equations represent
      • General equation: \ (^ X ^ 2 + Y 2 + Dx + = 0 the Ey + F. \)
      • Standard equation: \ ((X-x_0) ^ 2 + (Y-y_0) R & lt ^ 2 ^ 2 = \)
  • CSlope CBias classes and categories : To solve the slope represents the slope of the straight line to infinity, b and k specific case invalid is true infinite design, and isinf isNan. Since you slope packet, CSlope to achieve less than operator.
  • CPoint Class : represents the intersection of a key map is necessary to realize the less than operator.

(C) the key functions

  • inputShapes : processing an input function, the slope of the straight line by packet, into map<double, set<CLine>>the _k2linesmiddle
    circle directly into set<CCircle>the _circlesinside.
  • calcShapeInsPoint : find two graphics function intersections, three cases, the return point vector.
    • Straight line and a straight line
    • Linear and circular
    • Round and round
  • cntTotalInsPoint : find all the focus function, the order after the first round request, traversing a straight line focus. It has traversed to join a graphics overset.
    • Two straight pruning:
      • Cut parallel: each of the parallel set were sequentially added, without computing the intersection of the straight line within the group, only traverse overcentralized other non-parallel lines.
      • Cut total points: If the point total of ABC, ABC order traversal, first calculate the AB, the intersection is P; also found that the intersection P, there is no need to calculate the intersection when BC After calculating the AC. A method for maintaining _insp2shapesthis map<CPoint, set<CShape>>data structure, it passes to the intersection of the line set mappings.
    • Again, traversing the circle of violence seeking focus. Added _insp2shapesin
    • Function returns _insp2shapes.size()is the number of intersections.

(D) Test Design

According to the plan implementation of the code, it has achieved three parts function, namely to achieve complete the test, the test that is submitted by. Test pipeline as a function of particle size. Test data and code have been uploaded github.

  1. test_input: 4 constructed test data, test input function inputShapes function, in which a test sample the following, explanation see Notes:

    Covering the single line test, conventional, concurrent, parallel

    TEST_METHOD(TestMethod4)
         {
             // paralile 数据为两组平行线
             // 4
             // L 0 0 0 1
             // L 0 0 1 1
             // L 1 0 1 2
             // L 1 0 2 1
             //直线一般方程ABC答案集
             vector<CLine> ans;
             ans.push_back(CLine(1, -1, 0));
             ans.push_back(CLine(1, -1, -1));
             ans.push_back(CLine(1, 0, 0));
             ans.push_back(CLine(2, 0, -2));
             //直线斜率答案集
             vector<CSlope> ans_slope;
             ans_slope.push_back(CSlope(1.0));
             ans_slope.push_back(CSlope(true));
             ifstream fin("../test/test4.txt");//读测试输入文件
             if (!fin) {//确认读入正确
                 Assert::AreEqual(132, 0);
             }
             //测试开始
             CIntersect ins;
             ins.inputShapes(fin);
             //获取测试目标数据结构
             map<CSlope, set<CLine> > k2lines = ins.getK2Lines();
             //对比答案
             Assert::AreEqual((int)k2lines.size(), 2);
             int i = 0;
             int j = 0;
             for (map<CSlope, set<CLine> >::iterator mit = k2lines.begin();
                                     mit != k2lines.end(); ++mit, ++i) {
                 Assert::AreEqual(true, mit->first == ans_slope[i]);
                 Assert::AreEqual((int)(mit->second.size()), 2);
                 set<CLine> lines = mit->second;
                 for (set<CLine>::iterator sit = lines.begin(); 
                                 sit != lines.end(); ++sit, ++j) {
                     Assert::AreEqual(true, ans[j] == *sit);
                 }
             }
         }
  2. test_line_intersect: 4 test sample configuration, function test intersection of two lines calcShapeInsPoint, the code slightly

    Covering the single line test, conventional, concurrent, parallel

  3. test_cnt_intersect: test sample structure 11, the total number of test functions cntTotalInsPoint, sample code

    Covering the single line test, conventional, common point, in parallel, floating point precision, both inside and outside the cut, cut three lines at one point, the pressure test

    TEST_METHOD(TestMethod9)
         {
             // 相切测试,含内切、外切、直线两圆三线切于一点
             // 6
             // C 0 0 10
             // C 4 3 5
             // C - 5 0 5
             // L 2 14 14 - 2
             // L 0 0 0 1
             // L - 10 0 - 10 1
             ifstream fin("../test/test9.txt");
             if (!fin) {
                 Assert::AreEqual(132, 0);
             }
             CIntersect ins;
             ins.inputShapes(fin);
             int cnt = ins.cntTotalInsPoint();
             Assert::AreEqual(9, cnt); // 总数为9
         }

Fifth, performance improvements and the elimination of all alarms

(A) Improved Performance

The performance of the detector running VS2017, view the performance bottleneck of their own code.

Visible total run time-consuming 38s, the most time-consuming function cntTotalInsPoint , following a careful analysis of this function, identify performance bottlenecks.

analysis:

Performance bottlenecks can be seen in map<CPoint, set<CShape>>the _insp2shapesinsertion and search variables, through careful analysis, this variable can be optimized:

  • Since the effect of this variable is given by the intersection, find the intersection of the line through this, because I can be uniquely determined by a CShape id, so you can direct deposit int, and set<CShape>can be changedset<int>

  • Secondly, this set is not required to find, just add, as well as the overall copy, so do not need a set, you can change the vector. set before inserting a need to traverse the red-black tree takes a lot of memory. So the original map<CPoint, set<CShape>>changed map<CPoint, vector<int>>.
  • Similarly, this map<CSlope, set<CLine>>can be changed map<CSlope, vector<CLine>>.

Performance analysis of the modified

As can be seen, the total run time was reduced from 38 to 27, performance improved significantly.

Before the specific code number is sampled also reduced, it produces a visible modify performance.

(Ii) Elimination of alarm

Eliminate pre-alarm:

After eliminating the alarm:

VI Code Description

(A) Floating-point comparison process

Float is well known in the computer can not be directly compared equal, equal to the common floating-point comparison method

#define EPS 1e-6
double x;
double y;
if (abs(x-y) < EPS) {
  cout << "x == y" << endl;
}

This ensures that within a certain floating-point errors, two floating-point numbers are considered equal.

In this demand, a number of floating-point involves Class should override <operator. Its code needs to consider the floating point error problem. CPoint e.g. less than operator class code as follows:

bool CPoint::operator < (const CPoint & rhs) const 
{ // 要求仅当 _x < rhs._x - EPS 或 _x < rhs._x + EPS && _y < rhs._y - EPS 时返回true
    if (_x < rhs._x - EPS || _x < rhs._x + EPS && _y < rhs._y - EPS) {
        return true;
    }
    return false;
}

(Ii) Find the intersection of two lines: a straight line and the straight line or straight line or circle circle circle

// calculate all intersect points of s1 and s2
// return the points as vector
// need: s1, s2 should be CLine or CCircle.
// special need: if s1, s2 are CLine. They cannot be parallel.
std::vector<CPoint> CIntersect::calcShapeInsPoint(const CShape& s1, const CShape& s2) const
{
    if (s1.type() == "Line" && s2.type() == "Line") { // 直线交点公式,输入要求两线不平行
        double x = (s2.C()*s1.B() - s1.C()*s2.B()) / (s1.A()*s2.B() - s2.A()*s1.B());
        double y = (s2.C()*s1.A() - s1.C()*s2.A()) / (s1.B()*s2.A() - s2.B()*s1.A());
        vector<CPoint> ret;
        ret.push_back(CPoint(x, y));
        return ret;
    }
    else {
        if (s1.type() == "Circle" && s2.type() == "Line") {
            return calcInsCircLine(s1, s2);
        }
        else if (s1.type() == "Line" && s2.type() == "Circle") {
            return calcInsCircLine(s2, s1);
        }
        else { // 两个圆的交点转化为一个圆与公共弦直线的交点
            CLine line(s1.D() - s2.D(), s1.E() - s2.E(), s1.F() - s2.F());
            return calcInsCircLine(s1, line);
        }
    }
}
// calculate Intersections of one circ and one line
// need: para1 is CCirc, para2 is CLine
// return a vector of intersections. size can be 0,1,2.
std::vector<CPoint> calcInsCircLine(const CShape& circ, const CShape& line)
{
    if (line.k().isInf()) { // 斜率无穷,略
        ...
    }
    else if (abs(line.k().val() - 0.0) < EPS) { //斜率为0,略
        ...
    }
    else {
        vector<CPoint> ret;
        double k = line.k().val();
        double x0 = circ.x0();
        double y0 = circ.y0();
        double b1 = line.b().val();
        double d_2 = (k * x0 - y0 + b1) * (k * x0 - y0 + b1) / (1 + k * k); 
        double d = sqrt(d_2); // 圆心到直线距离
        double n; // 半弦长
        if (d - circ.r() > EPS) { // not intersect
            return ret;
        }
        else if (circ.r() - d < EPS){ // tangent
            n = 0.0;
        }
        else { // intersect 
            n = sqrt(circ.r() * circ.r() - d_2);
        }
        double b2 = x0 / k + y0;
        double xc = (b2 - b1) / (k + 1 / k); // 弦中点x坐标
        double yc = (k * b2 + b1 / k) / (k + 1 / k); // 弦中点y坐标
    // 交点坐标
        double x1 = xc + n  / sqrt(1 + k * k);
        double x2 = xc - n  / sqrt(1 + k * k);
        double y1 = yc + n * k / sqrt(1 + k * k);
        double y2 = yc - n * k / sqrt(1 + k * k);
        ret.push_back(CPoint(x1, y1));
        ret.push_back(CPoint(x2, y2));
        return ret;
    }
}

(C) parallel to the intersection of a packet and common pruning

// the main pipeline: loop the inputs and fill in _insp2shapes or _insPoints
// return the total count of intersect points
// need: _k2lines and _circles have been filled
int CIntersect::cntTotalInsPoint()
{
    // lines first
    vector<CLine> over;
    for (auto mit = _k2lines.begin(); mit != _k2lines.end(); ++mit) { // 遍历平行组
        vector<CLine>& s = mit->second;
        for (auto sit = s.begin(); sit != s.end(); ++sit) { //遍历组内直线
            // trick: If the cross point already exists, 
            //        we can cut calculation with other lines crossing this point.
            set<int> can_skip_id; // use this to record which line do not need calculate.
            for (auto oit = over.begin(); oit != over.end(); ++oit) { // 遍历over集
                if (can_skip_id.find(oit->id()) == can_skip_id.end()) { // cannot skip
                    CPoint point = calcShapeInsPoint(*sit, *oit)[0]; // must intersect // 能保证不平行
                    if (_insp2shapesId.find(point) == _insp2shapesId.end()) { // 全新交点
                        _insp2shapesId[point].push_back(sit->id());
                        _insp2shapesId[point].push_back(oit->id());
                    }
                    else { // cross point already exists 交点已存在
                        vector<int>& sl = _insp2shapesId[point];
                        can_skip_id.insert(sl.begin(), sl.end()); // 下次遇到可以跳过不算
                        _insp2shapesId[point].push_back(sit->id());
                    }
                }
            }
        }
        over.insert(over.end(), s.begin(), s.end());// 整个平行组加入over集
    }
  // 后面算圆略
  ...
}

Seven, thinking

  • How much more elegant solution to calcShapeInsPoint classification, c ++ classes to keep strong rotor.
    • By transfer pointer can do, but not very convenient.
    • Less than the full functions can be done by writing in the base class, not very good. (The current implementation)
  • The use of the complexity of the map and c ++ STL SET, with the underlying red-black tree are implemented as O (n). In discussing the exchange found, c ++ 11 standard also added a similar java HashSet and HashMap in the STL function, namely unordered_map and unordered_set. This complexity is O (1) in a good case. Remember to use next time.

Guess you like

Origin www.cnblogs.com/old-jipa-deng/p/12453287.html