el blog de proyectos individuales

proyecto individual - buscando el número de intersección

proyecto contenido
Esta obra pertenece cursos Primavera 2020 Computer Software Engineering Institute (Roger Ren Jian)
Cuando este requisito en el trabajo proyecto de trabajo individual
Mi objetivo en este curso es Aprender la ingeniería de software forma de pensar, al software de escritura buena y mantenimiento
En aspectos particulares de la tarea que me ayudó a alcanzar las metas Familiarizados con el proceso de escribir código en funciones de Visual Studio y el uso de varias funciones como C ++ y revisado algunos conocimientos algoritmos.
clase 006
dirección del proyecto gitHub

Una estimación .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
· Estimación • Calcular la cantidad de tiempo esta tarea requiere 600 990
Desarrollo desarrollar
· Análisis · Análisis de Necesidades (incluyendo el aprendizaje de nuevas tecnologías) 180 480
· Diseño de especificaciones Generar documentos de diseño 60 60
· Revisión de diseño · Revisión de Diseño (y sus colegas revisaron los documentos de diseño) 20 10
· Codificación Estándar · Especificaciones de códigos (desarrollo de normas apropiadas para el desarrollo actual) 20 10
· Diseño · Diseño específico 40 80
· Codificación · Codificación específica 120 240
· Revisión de código · Revisión Código 20 30
· Prueba · Test (autoprueba, modificar el código, enviar modificaciones) 60 40
la presentación de informes informe
· Informe de prueba · Informe de prueba 30 15
· Medida del tamaño · Cargas de trabajo informáticas 30 20
· Postmortem y Plan de Mejora de Procesos · La retrospección, y proponer plan de mejora de procesos 20 5
total 600 990

Ideas II.

La primera idea es conseguir que la violencia para resolver este problema, porque después de todo el procesamiento de la entrada guardar arriba y hacia veintidós calcular la intersección, el cruce se almacena como un mapa de teclado, asigne el tamaño de las estadísticas finales puede ser. Pero después de ver los datos dudado, 1000 para el siguiente grupo, este algoritmo no es ningún problema, pero siempre y cuando cuidadoso cálculo, la precisión puede ser garantizada, pero la parte de rendimiento, pero completamente impracticable. Encuentra las intersecciones de la línea recta veintidós complejidad es O (n ^ 2), que también resultados en los datos es mayor que 10.000, la velocidad es muy lenta, y mucho menos un conjuntos de datos máximos 500.000. Así que busqué la Internet alguna información, el único problema está relativamente cerca de la intersección de una línea de exploración demanda segmento de línea, su complejidad tiempo es (k + n) log n, donde n es el número de segmentos, k es el número de intersección en esta tarea a tiempo para cumplir con los requisitos, por lo que decidí adoptar métodos violentos para calcular el grupo de 1000, con el fin de garantizar la corrección del algoritmo, y la parte de rendimiento, el escaneo de línea de algoritmo para mejorar la velocidad de funcionamiento.

III. Aplicación Diseño

1. La violencia encontrar las intersecciones

Mi aplicación es la construcción de dos clases son la clase y la clase clase Circle Line, Línea en donde dos coordenadas de la entrada en ecuaciones lineales en la forma Ax + By + C = 0; y la clase Circle también hacen lo mismo trabajo, forman sustancialmente un círculo ecuación $ (xm) ^ 2 + (yn) ^ 2 = r ^ 2 $. Línea con después de leer los datos almacenados relacionados con el Círculo o variable, serán incorporados a un vector de clase, el extremo lejano de procesamiento previo.

Después de veintidós años se va a llevar a cabo para encontrar las intersecciones. En primer lugar, tomar dos líneas diferentes de la colección de la línea, a continuación, dos líneas rectas se calcula llamando a la intersección calculate_line_line método, la idea es muy simple, matemáticas de la escuela media, no mucho entrar en detalles, el segundo paso calculan en línea recta y un círculo de intersección, a partir juego línea sacado un círculo y una línea, se calcula mediante una llamada al calculate_line_circle método y una línea de la intersección de un conjunto círculo círculo, el proceso es la solución de ecuaciones simultáneas ecuación; finalmente el cálculo de la intersección de dos círculos, desde el círculo conjunto quitar los dos círculos diferentes, y la llamada al método intersección calculate_circle_circle calculado, la idea del método es la solución simultánea de las ecuaciones. Estos tres pasos a repetirse n veces para asegurar que cualquier lado dos geometrías están buscando a través de la intersección, y la intersección de estos valores como inserto de llave en el mapa, el mapa se eliminará automáticamente intersección duplicado, el tamaño del mapa es el último número de la intersección

Función de cálculo si tres principales pruebas de la unidad de pruebas intersección calcular correctamente el punto de intersección. Por tanto, yo calculate_line_line, calculate_line_circle, valor de retorno calculate_circle_circle a int, y se construyó como sigue las pruebas de unidad de prueba:

TEST_METHOD(calculate_line_line)
        {
            Calculate cal;
            Line l1(0, 0, 1, 1);
            Line l2(0, 0, 0, 1);
            int ret = cal.calculate_line_line(l1, l2);
            Assert::AreEqual(ret,(int)1);
            Line l3(0, 0, 1, 1);
            Line l4(1, 0, 2, 1);
            ret = cal.calculate_line_line(l3, l4);
            Assert::AreEqual(ret, (int)0);
        }

Aquí la prueba es si la intersección de las dos líneas rectas se calcula correctamente, una consideración especial y una línea recta paralela a la pendiente de la caja libre, los espectáculos de código que pasan la prueba.

TEST_METHOD(calculate_line_circle)
        {
            Calculate cal;
            Line l1(0, 0, 1, 1);
            Circle c1(0, 1, 1);
            int ret = cal.calculate_line_circle(l1, c1);
            Assert::AreEqual(ret, (int)2);
            Line l2(0, 0, 0, 1);
            Circle c2(1, 0, 1);
            ret = cal.calculate_line_circle(l2, c2);
            Assert::AreEqual(ret, (int)1);
            Line l3(0, 0, 1, 0);
            Circle c3(0, 2, 1);
            ret = cal.calculate_line_circle(l3, c3);
            Assert::AreEqual(ret, (int)0);
        }

Aquí la prueba es si una línea recta y un cálculo de la intersección circular correctamente, una consideración especial no es pendiente lineal, así como el círculo y la prueba de la línea tiene dos, uno, cero punto de intersección, el código pasa la prueba.

TEST_METHOD(calculate_circle_circle)
        {
            Calculate cal;
            Circle c1(0, 0, 1);
            Circle c2(1, 1, 1);
            int ret = cal.calculate_circle_circle(c1, c2);
            Assert::AreEqual(ret, (int)2);
            Circle c3(0, 0, 2);
            Circle c4(3, 0, 1);
            ret = cal.calculate_circle_circle(c3, c4);
            Assert::AreEqual(ret, (int)1);
            Circle c5(0, 0, 3);
            Circle c6(0, 0, 1);
            ret = cal.calculate_circle_circle(c5, c6);
            Assert::AreEqual(ret, (int)0);
            Circle c7(0, 0, 1);
            Circle c8(0, 9, 1);
            ret = cal.calculate_circle_circle(c7, c8);
            Assert::AreEqual(ret, (int)0);
        }

Si la prueba es calcular correctamente la intersección de dos círculos, considerados los dos círculos tienen dos, uno, cero punto de intersección, sino también considerar el caso en que un círculo dentro de otro círculo, el código pasa la prueba.

Hasta el momento final de la unidad de prueba, y también he hecho un poco de entrada salida de prueba a través de salida de todas las coordenadas de intersección, y luego con los resultados del sitio de GeoGebra de comparación y encontró el cálculo es exacto.

2. algoritmo de línea de escaneado

while (!q.empty()) {
            Point p = q.top();
            q.pop();
            if (p.type == 1) {//是左端点
                s.insert(p.belong);
                set<Line,cmp2>::iterator iter;
                iter = s.find(p.belong);
                Line l = *iter;
                if (iter != s.begin()) {
                    iter--;
                    Line l1 = *iter;
                    iter++;
                    calculate.calculate_line_line_allinsert(l, l1);
                }
                iter++;
                if (iter != s.end()) {
                    Line l1 = *iter;
                    calculate.calculate_line_line_allinsert(l1, l);
                } 
            }
            else if (p.type == 2) {//是右端点
                set<Line, cmp2>::iterator iter,iter1,del;
                iter = s.find(p.belong);
                iter1 = iter;
                del = iter;
                iter1++;
                if (iter != s.begin() && iter1 != s.end()) {
                    iter--;
                    Line l1 = *iter;
                    Line l2 = *iter1;
                    calculate.calculate_line_line_allinsert(l2, l1);
                }
                s.erase(del);
            }
            else {//是交点
                pointset.insert(p);
                set<Line, cmp2>::iterator iter1, iter2, it1, it2;
                iter1 = s.find(p.father1);
                iter2 = s.find(p.father2);
                it1 = iter1;
                it2 = iter2;
                it1++;
                if (it1 != s.end()) {
                    Line l1 = *it1;
                    Line l2 = *iter2;
                    calculate.calculate_line_line_allinsert(l1, l2);
                }
                if (iter2 != s.begin()) {
                    it2--;
                    Line l1 = *iter1;
                    Line l2 = *it2;
                    calculate.calculate_line_line_allinsert(l1, l2);
                }
            }
        }
        cout << pointset.size() << endl;

Aunque el algoritmo de línea de exploración terminó, pero se encontró con la velocidad no mejora, en el caso de grandes cantidades de datos de alta velocidad, pero inferior a la violencia, no sé por qué, sólo tuvo que enfoque el uso de la violencia.

IV. Análisis del Rendimiento

Primeros datos de un 500.000, si el uso de la violencia en O (n ^ 2), entonces la única intersección en el final de cómo optimizar el tratar de reducir la cantidad de cada ciclo de cálculo no mejora el rendimiento tanto, necesitan ser reemplazados con el fin de mejorar el rendimiento y mejores algoritmos. Así que pasé cerca de cuatro horas para aprender las líneas de exploración (Bentley-Ottmann) algoritmo, pero por desgracia no sé el conjunto final de los problemas de rendimiento o en mal, siempre complejidad equivocado (a menudo también mucho más lenta que la violencia), complejo original grado debe ser O (nlogn + klogn), donde n es el número de línea recta, k es el número de intersecciones, la complejidad de la parte 5000 y 500000, obviamente, debe más rápido que 5000 * 5000, pero el hecho de que las órdenes más lentos violentos de magnitud , tuve que abandonar. Esperanza de conseguir ta señalador.

gráfico de análisis de rendimiento publica a continuación la solución de la violencia

imagen-20200310001516383

Para un conjunto de datos de 6000 necesidades para funcionar 1 minuto

imagen-20200310001607038

La mayoría de las veces está ocupada por la función principal no hay duda, porque en el fondo todo el procesamiento en el principal, el que más tiempo para eliminar la ocupación principal es calcular la intersección de dos rectas, rectas tengo este conjunto de datos, por lo que representa esta función durante un máximo de .

imagen-20200310002808050

Uno de los que más tiempo consume es la intersección de la inserción en el mapa, así que quiero ser capaz de mejorar aquí.

Por lo tanto los intentos de reemplazar el mapa es un conjunto, utilizando los mismos datos, los siguientes resultados.

imagen-20200310004816027

Se encontró que el tiempo total se acorta

imagen-20200310004836606

La proporción de cada función es casi ningún cambio, pero el tiempo ha cambiado un poco corto.

imagen-20200310004915153

Como un conjunto de se reduce mucho tiempo punto de inserción, a continuación, creemos que estableció una serie de mejor rendimiento, el conjunto de elección final.

V. Código Descripción

La función clave es calcular la intersección de código, que se divide en: la intersección de las dos líneas rectas se calcula, se calcula la intersección de dos cálculo de la intersección circular, así como un círculo y una línea recta, se describirá a continuación son parte de las tres funciones.

1. La intersección de las dos líneas rectas se calcula

int Calculate::calculate_line_line(Line l1,Line l2) {//caculate the crosspoint of the two lines 
    //int is eazy to test
    crosspoint point;
    if (l1.A * l2.B == l1.B * l2.A) {
        return 0;
    }
    else {
        point.y = (l1.A * l2.C - l1.C * l2.A) / (l1.B * l2.A - l1.A * l2.B);
        if (l1.A == 0) {
            point.x = (-l2.C - point.y * l2.B) / l2.A;
        }
        else {
            point.x = (-l1.C - point.y * l1.B) / l1.A;
        }
        pointmap.insert(pair<crosspoint, int>(point, 1));
        return 1;
    }
}

En primer lugar, el valor de retorno de esta función es de tipo int, porque quería ver si se calcula con precisión en las pruebas unitarias. En el tiempo de ejecución, independientemente de esto estoy valor de retorno int. Mi idea está procesando la clase de línea de entrada dos parámetros, de acuerdo con la fórmula de la fórmula general para encontrar las intersecciones, se puede determinar sin un cruce o intersección como punto de intersección valores Inserte la llave en el mapa, el mapa determinará automáticamente si existe una intersección, si es que existe, ya no es el mapa de la adición, o mapa añadió esta intersección.

2. una línea recta y un cálculo de la intersección circular

crosspoint point1;
    crosspoint point2;
    double a = l.A * l.A + l.B * l.B;
    double b = 2 * (l.B * l.A * c.n - l.B * l.B * c.m + l.A * l.C);
    double k = l.B * l.B * (c.m * c.m + c.n * c.n - c.r * c.r) + l.C * l.C + 2 * l.B * l.C * c.n;
    double deta = b * b - 4 * a * k;
    if (deta > 0) {
        point1.x = (sqrt(deta) - b) / (2 * a);
        point2.x = (-1 * sqrt(deta) - b) / (2 * a);
        point1.y = (-l.C - l.A * point1.x) / l.B;
        point2.y = (-l.C - l.A * point2.x) / l.B;
        pointmap.insert(pair<crosspoint, int>(point1, 1));
        pointmap.insert(pair<crosspoint, int>(point2, 1));
        return 2;
    }
    else if (deta == 0) {
        point1.x = (b == 0) ? 0 : -1 * b / (2 * a);
        point1.y = (-l.C - l.A * point1.x) / l.B;
        pointmap.insert(pair<crosspoint, int>(point1, 1));
        return 1;
    }
    else {
        return 0;
    }

Y la búsqueda de una línea de intersección de un círculo o un solucionador de ecuaciones simultáneas, se observa que, después de una ecuación simultánea es una ecuación de segundo grado, la forma: ax ^ 2 + bx + t = 0 tenemos que ser calculado de acuerdo a la fórmula, en el que deta = b ^ 2-4 * a * t, deta si el valor es mayor que 0, entonces la ecuación tiene dos soluciones, una solución es igual a 0, o ninguna solución. Según esta clasificación se calculan después de DETA, la obtención de un valor de X, los valores de y y luego de vuelta a la ecuación se determina, las coordenadas de intersección como el valor de clave en el mapa.

3. Cálculo de la intersección de dos círculos

int Calculate::calculate_circle_circle(Circle c1, Circle c2) {//calculate the crosspoint of the two circles
    crosspoint point1;
    crosspoint point2;
    if (c2.n == c1.n && c2.m == c1.m) {
        return 0;
    }
    else if (c2.n == c1.n) {
        double temp = ((double)c2.m * c2.m - (double)c1.m * c1.m + (double)c2.n * c2.n - (double)c1.n * c1.n + (double)c1.r * c1.r - (double)c2.r * c2.r)
            / ((double)2 * ((double)c2.m - c1.m));
        point1.x = temp;
        point2.x = temp;
        double left = (double)c1.r * c1.r - (temp - c1.m) * (temp - c1.m);
        if (left > 0) {
            point1.y = sqrt(left) + c1.n;
            point2.y = c1.n - sqrt(left);
            pointmap.insert(pair<crosspoint, int>(point1, 1));
            pointmap.insert(pair<crosspoint, int>(point2, 1));
            return 2;
        }
        else if (left == 0) {
            point1.y = c1.n;
            pointmap.insert(pair<crosspoint, int>(point1, 1));
            return 1;
        }
        else {
            return 0;
        }
    }
    else {
        double k = ((double)c1.m - c2.m) / ((double)c2.n - c1.n);
        double temp = ((double)c2.m * c2.m - (double)c1.m * c1.m + (double)c2.n * c2.n - (double)c1.n * c1.n + (double)c1.r * c1.r - (double)c2.r * c2.r)
            / ((double)2 * ((double)c2.n - c1.n));
        double a = 1 + k * k;
        double b = 2 * (k * temp - c1.n * k - c1.m);
        double c = (double)c1.m * c1.m + (double)c1.n * c1.n - (double)c1.r * c1.r + temp * temp - 2 * temp * c1.n;
        double deta = b * b - 4 * a * c;
        if (deta > 0) {
            point1.x = (sqrt(deta) - b) / (2 * a);
            point2.x = (-1 * sqrt(deta) - b) / (2 * a);
            point1.y = point1.x * k + temp;
            point2.y = point2.x * k + temp;
            pointmap.insert(pair<crosspoint, int>(point1, 1));
            pointmap.insert(pair<crosspoint, int>(point2, 1));
            return 2;
        }
        else if (deta == 0) {
            point1.x = (b == 0) ? 0 : -1 * b / (2 * a);
            point1.y = point1.x * k + temp;
            pointmap.insert(pair<crosspoint, int>(point1, 1));
            return 1;
        }
        else {
            return 0;
        }
    }
}

La búsqueda de la intersección de dos círculos con una línea y un círculo, pero los parámetros más complejos solamente, es derivación completamente matemática, y por lo tanto no se describe en detalle aquí.

Supongo que te gusta

Origin www.cnblogs.com/Boming/p/12453226.html
Recomendado
Clasificación