operaciones de proyectos individuales $ \ cdot $ buscan el número de intersección

proyecto de trabajo individual \ (\ cdot \) buscando el número de intersección

I. Introducción a las necesidades operacionales

El trabajo es un trabajo de proyecto personal en cursos de ingeniería de software Northern College of Computer, capacidades de desarrollo personal para los equipos de desarrollo de software es crítica, esta objetivos del proyecto para que los estudiantes puedan aprender técnicas comúnmente utilizadas por los desarrolladores individuales que buscan una geometría de la intersección de la demanda como método de PSP, análisis de requisitos, documentación de diseño, codificación, implementación, prueba, evaluación de desempeño y así sucesivamente.

proyecto contenido
Esta obra pertenece a los cursos de ingeniería de software del Norte Parque de blogs blog de clase
Por favor, haga clic en el enlace para ver los requisitos del trabajo proyecto de trabajo individual
Clase: 006 Muestra
dirección de GitHub IntersectProject
Mi objetivo de este curso es Capacidad para obtener como ingeniero de software
En aspectos particulares de la tarea que me ayudó a alcanzar las metas Resumiendo el pasado, la planificación para el futuro

Dos, forma PSP

PSP2.1 Etapas del Proceso de Software Personal Estimado de consumo de tiempo (minutos) Los que consumen mucho tiempo reales (minutos)
Planificación plan 90 83
· Estimación • Calcular la cantidad de tiempo esta tarea requiere 90 83
Desarrollo desarrollar 830 1320
· Análisis · Análisis de Necesidades (incluyendo el aprendizaje de nuevas tecnologías) 30 60
· Diseño de especificaciones Generar documentos de diseño 60 40
· Revisión de diseño · Revisión de Diseño (y sus colegas revisaron los documentos de diseño) 60 60
· Codificación Estándar · Especificaciones de códigos (desarrollo de normas apropiadas para el desarrollo actual) 20 20
· Diseño · Diseño específico 60 120
· Codificación · Codificación específica 240 480
· Revisión de código · Revisión Código 0 0
· Prueba · Test (autoprueba, modificar el código, enviar modificaciones) 360 540
la presentación de informes informe 180 240
· Informe de prueba · Informe de prueba 30 180
· Medida del tamaño · Cargas de trabajo informáticas 30 30
· Postmortem y Plan de Mejora de Procesos · La retrospección, y proponer plan de mejora de procesos 120 30
total 1100 1560

En tercer lugar, la resolución de problemas Descripción de ideas

Tema breve demanda

  • necesidades de título, las líneas rectas dadas, encontrar el número de la intersección
  • El número de línea recta1000 <= N <= 500000
  • El número de intersección0 <= h <= 5000000
  • Un largo tiempo de funcionamiento 60

Ideas de resolución de problemas

Para obtener el título de la violencia primer pensamiento resuelto, entre dos calcular la intersección, y luego ir pesada. Pero esto es pura \ (O (n ^ 2) \) la complejidad, necesariamente el TLE. El pensamiento de querer cambiar que no esperaba lo peor de la complejidad de la naturaleza (O (n ^ 2) \ ) \ algoritmo. Así comprobaron en línea alguna información y se encontró que Internet tiene un importante tema limitado, no existe punto común de tres hilos. Pero exigimos este tema es permitir a un total de puntos de tres hilos, no ayudó.

Después de ver el número de intersecciones 0 <= h <= 5000000de limitación, quizás lo peor sensación complejidad \ (O (n ^ 2) \) solución algoritmo no es imposible, porque si hay N = 500000líneas rectas no existen tres líneas de punto común y paralela a ella, hace allí \ (N (N-1) / 2 \) intersecciones, pero la razón por qué el número de intersecciones se limita h <= 5000000, que muestra un gran número de concurrente multi-línea y paralelo .

¿Quiere seguir en esta línea de pensamiento, podemos en la violencia \ (O (n ^ 2) \) consideran algoritmo basado en la simultánea de varias líneas y en paralelo situación podado, la complejidad del tiempo específico después de la poda es más complejo no calculo, pero debe ser el tiempo para cumplir con las condiciones, el documento será sometido a pruebas de resistencia.

En cuarto lugar, los documentos de diseño

(一) de tuberías

preproceso

  • ReadShape : leer el archivo de entrada que recibe toda lineal y circular
  • Construir la Forma : la forma del objeto basado en el constructo de entrada, se calcula la pendiente.
  • Slope por clasificados : la pendiente del paquete de prensa lineal guardados.

CalcIntersect

  • CalcLines : calcular la intersección entre todas las líneas:
    • Secuencialmente teniendo en cuenta cada uno de los grupos paralelos, cada línea atravesada por el cálculo de la intersección. Las líneas paralelas en el grupo sin intersección cálculo.
    • Compruebe la tabla de intersección, si está presente, no pueden buscar otras líneas de la misma intersección.
      intersección tabla: mapa <puntos, Set <línea >>
      Mantenimiento tabla de intersección: Añadir nueva tabla de intersección intersección, unión de línea mesa de juego de la línea correspondiente
  • CalcCircles : cuentan después de todas las líneas, y uno transversal redonda a continuación. Encontrar a todo tipo de violencia antes de su intersección con los gráficos.
  • Cuando se calcula el punto de la línea recta y el círculo de intersección, la poda puede ser de la siguiente manera:
    Considere el círculo de intersección con una familia de líneas paralelas, líneas paralelas podrían interceptar especie de grupo B1, B2, B3 \ (\ cdots \)
    si el inicio de la circular bi de, i es mayor que una cierta fase de la línea, de todos modos, es más pequeño que viceversa.

(Ii) entre el diagrama de clases UML

  • categorías CIntersect : Implementar flujo de control, comprendiendo el procedimiento una entrada , calcula el punto de los dos patrones de intersección , el cálculo del número total de intersección
  • CShape categorías : clase base gráfica, crear un identificador único para cada instancia de gráfico
  • clases Cline CCircle y categorías : patrón de herencia de la clase base, actúan como parámetros que muestra la forma de ecuaciones algebraicas.
  • Dos representaciones lineales ecuación
    • ecuación general: \ (Ax de + By + C = 0 \)
    • ecuación truncado: \ (Y = KX + B \)
    • En ambas ecuaciones representan
      • ecuación general: \ (^ X ^ 2 + Y 2 + Dx + = 0 el Ey + F. \)
      • ecuación estándar: \ ((X-x_0) ^ 2 + (Y-y_0) R & lt ^ 2 ^ 2 = \)
  • clases CSlope CBias y categorías : Para resolver la pendiente representa la pendiente de la línea recta hasta el infinito, b y k caso específico no válida es cierto diseño infinito, y isinf isNaN. Puesto que usted paquete pendiente, CSlope para alcanzar menos del operador.
  • PuntoC Clase : representa la intersección de un mapa de teclado es necesario darse cuenta de la menor de operador.

(C) las funciones de las teclas

  • inputShapes : procesamiento de una función de entrada, la pendiente de la línea recta por paquete, en map<double, set<CLine>>el _k2linesmedio
    círculo directamente en set<CCircle>el _circlesinterior.
  • calcShapeInsPoint : encontrar dos gráficos funcionan intersecciones, tres casos, el vector de punto de retorno.
    • línea recta y una línea recta
    • Lineales y circulares
    • Vueltas y vueltas
  • cntTotalInsPoint : encontrar toda la función de enfoque, el orden después de la primera ronda de solicitud, que atraviesa un foco lineal. Se ha atravesado para unirse a un gráfico overconjunto.
    • Dos poda recta:
      • paralelas cortadas: se añadieron cada uno de los conjunto paralelo secuencialmente, sin calcular la intersección de la línea recta dentro del grupo, solamente traverse overcentralizada otras líneas no paralelas.
      • Cortar el total de puntos: Si el total de puntos de ABC, ABC orden de recorrido, primero calcular la AB, la intersección es P; también encontró que la intersección P, no hay necesidad de calcular la intersección cuando BC Después de calcular el AC. Un procedimiento para mantener _insp2shapesesta map<CPoint, set<CShape>>estructura de datos, pasa a la intersección de las asignaciones de conjunto de líneas.
    • Una vez más, atravesando el círculo de la violencia foco búsqueda. Añadido _insp2shapesen
    • devuelve la función _insp2shapes.size()es el número de intersecciones.

Diseño Ensayo (d)

De acuerdo con el plan de aplicación del código, que ha logrado funcionan tres partes, a saber, lograr completar la prueba, la prueba que se presenta por. tubería de prueba como una función del tamaño de partícula. Los datos de prueba y el código han sido github cargado.

  1. test_input: 4 datos de prueba construidos, entrada de prueba de función inputShapes función, en el que una muestra de ensayo que sigue, véanse las notas explicativas Notas:

    Cubriendo la prueba de línea única, convencional, concurrente, paralelo

    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: configuración de ejemplo 4 de prueba, prueba de la función intersección de dos líneas calcShapeInsPoint, el código ligeramente

    Cubriendo la prueba de línea única, convencional, concurrente, paralelo

  3. test_cnt_intersect: test estructura de la muestra 11, el número total de funciones de prueba cntTotalInsPoint, código de ejemplo

    Cubriendo la prueba de línea única,, punto común convencional, en paralelo, precisión de punto, tanto dentro como fuera de la corte flotante, cortar tres líneas en un punto, la prueba de presión

    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
         }

En quinto lugar, mejoras en el rendimiento y la eliminación de todas las alarmas

(A) Rendimiento mejorado

El rendimiento del detector corriendo VS2017, ver el cuello de botella de su propio código.

run 38s visibles totales que consumen mucho tiempo, la función que más tiempo consume cntTotalInsPoint , después de un cuidadoso análisis de esta función, identificar los cuellos de botella de rendimiento.

análisis:

cuellos de botella de rendimiento se puede ver en map<CPoint, set<CShape>>las _insp2shapesvariables de inserción y búsqueda, a través de un cuidadoso análisis, esta variable puede ser optimizado:

  • Dado que el efecto de esta variable está dada por la intersección, encontrar la intersección de la línea a través de este, porque se puede determinar de forma única por un identificador de CShape, para que pueda dirigir int depósito, y set<CShape>puede ser cambiadoset<int>

  • En segundo lugar, este conjunto no está obligado a encontrar, simplemente agregar, así como la copia en general, por lo que no es necesario un conjunto, puede cambiar el vector. set antes de la inserción de una necesidad de recorrer el árbol rojo-negro tiene una gran cantidad de memoria. Así que el original map<CPoint, set<CShape>>ha cambiado map<CPoint, vector<int>>.
  • Del mismo modo, este map<CSlope, set<CLine>>puede ser cambiado map<CSlope, vector<CLine>>.

El análisis de rendimiento de la modificado

Como puede verse, el tiempo de funcionamiento total se redujo de 38 a 27, el rendimiento mejoró significativamente.

Antes de que el número de código específico se muestrea también redujo, produce un rendimiento de modificación visible.

(Ii) la eliminación de alarma

Eliminar la pre-alarma:

Después de la eliminación de la alarma:

Código Descripción VI

(A) proceso de comparación de punto flotante

Float es bien conocido en el equipo no puede ser directamente comparada iguales, igual al método de comparación de punto flotante común

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

Esto asegura que dentro de ciertos errores de punto flotante, dos números de coma flotante se consideran iguales.

En esta demanda, un número de coma flotante implica Clase debe pasar por encima <del operador. Su código debe tener en cuenta el problema de error de punto flotante. PuntoC por ejemplo menos de código de clase de operador como sigue:

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) Encontrar la intersección de dos líneas: una línea recta y la línea recta o una línea o un círculo círculo círculo recta

// 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) paralela a la intersección de un paquete y la poda común

// 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集
    }
  // 后面算圆略
  ...
}

Siete, el pensamiento

  • La cantidad de solución más elegante a la clasificación calcShapeInsPoint, clases de C ++ para mantener fuerte rotor.
    • Por transferencia puntero puede hacer, pero no es muy conveniente.
    • Menos de las funciones completas puede hacerse escribiendo en la clase base, no es muy bueno. (La implementación actual)
  • El uso de la complejidad del mapa y C ++ STL SET, con el árbol rojo-negro subyacente se implementan como O (n). Al discutir el intercambio Encontrado, C ++ 11 estándar también añade un java similares HashSet y HashMap en la función STL, a saber unordered_map y unordered_set. Esta complejidad es O (1) en un caso bueno. Recuerde que debe utilizar la próxima vez.

Supongo que te gusta

Origin www.cnblogs.com/old-jipa-deng/p/12453287.html
Recomendado
Clasificación