c++ - Bad precision creating dxf file - Stack Overflow

admin2025-04-09  0

I am working in an App for creating a Contour (Layer ar3pkt) that is a result of fitting ARCs and LINEs in the original Contour (Layer contour). The Layer (approx) is an intermediate step, that you can also see in my code.

It works, but I have the problem that the ARCs are not precise enought. They dont match the Intersection point with the next arc or line precisely. It seems like it works, but if I zoom in, there is a gap between consecutive elements. The gap measures 0.02 CAD units The whole object is 2000 CAD units big.

I added this:

dxfFile << std::fixed << std::setprecision(20);

at the beginning, but also not incrementing the precision.

std::ofstream dxfFile(filename);
dxfFile << std::fixed << std::setprecision(20);
    if (!dxfFile.is_open()) {
        std::cerr << "No se pudo abrir el archivo para escribir: " << filename << std::endl;
        return;
    }

    //Dateikopf DXF
    dxfFile << "0\nSECTION\n2\nHEADER\n0\nENDSEC\n";
    dxfFile << "0\nSECTION\n2\nTABLES\n";
    dxfFile << "0\nTABLE\n2\nLAYER\n";
    dxfFile << "0\nLAYER\n2\ncontour\n70\n0\n62\n1\n";// 
    dxfFile << "0\nLAYER\n2\napprox\n70\n0\n62\n3\n"; // 
    dxfFile << "0\nLAYER\n2\narc3pkt\n70\n0\n62\n7\n"; // 
    dxfFile << "0\nENDTAB\n0\nENDSEC\n";
    dxfFile << "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n";
    dxfFile << "0\nSECTION\n2\nENTITIES\n";

    // Alle Konturen als polyline schreiben
    for (const auto& contour : contours) {
        //glaettung approxPolyDP
            
        if (true)
        {
            std::vector<cv::Point> approx, fittedContour;
            double epsilon = 4;

            dxfFile << "0\nPOLYLINE\n8\ncontour\n66\n1\n70\n1\n";
            for (const auto& point : contour) {
                dxfFile << "0\nVERTEX\n8\ncontour\n10\n" << point.x << "\n20\n" << point.y << "\n30\n0.0\n";
            }
            dxfFile << "0\nSEQEND\n";

            cv::approxPolyDP(contour, approx, epsilon, true); // Glaettung 

            dxfFile << "0\nPOLYLINE\n8\napprox\n66\n1\n70\n1\n";
            for (const auto& point : approx) {
                dxfFile << "0\nVERTEX\n8\napprox\n10\n" << point.x << "\n20\n" << point.y << "\n30\n0.0\n";
            }
            dxfFile << "0\nSEQEND\n";     

            // Geraden und Bogen fitten
            for (size_t i = 0; i < approx.size(); i ++) {
               // Ajustar arco a 3 puntos
               cv::Point2f P0 = approx[i];
               cv::Point2f P1 = approx[(i + 1) % approx.size()];
               cv::Point2f P2 = approx[(i + 2) % approx.size()];

               //Berechnung der relative Laenge
               long double L1 = cv::norm(P1 - P0);
               long double L2 = cv::norm(P2 - P1);
               long double LRel = abs(L1 / L2);

               // Calcular el arco entre 3 puntos
               long double A = P1.x - P0.x;
               long double B = P1.y - P0.y;
               long double C = P2.x - P0.x;
               long double D = P2.y - P0.y;

               long double E = (A * (P0.x + P1.x) + B * (P0.y + P1.y)) / 2.0;
               long double F = (C * (P0.x + P2.x) + D * (P0.y + P2.y)) / 2.0;

               long double det = A * D - B * C;
               if (fabs(det) < 1e-9) continue;

               long  double cx = (D * E - B * F) / det;
               long double cy = (-C * E + A * F) / det;
               long double r = sqrt(pow(cx - P0.x, 2) + pow(cy - P0.y, 2));


               //Solo hay que cambiar esto, para que el angulo solo llege hasta el primerpunto
               long double ang1 = atan2(P0.y - cy, P0.x - cx);
               long double ang2 = atan2(P1.y - cy, P1.x - cx);

               // Asegurar que el arco es el menor posible
               long double anguloDiferencia = ang2 - ang1;
               if (anguloDiferencia < 0) {
                   anguloDiferencia += 2 * CV_PI;
               }
               if (anguloDiferencia > CV_PI) {
                  std::swap(ang1, ang2);
                  ang1 += 2 * CV_PI;
               }

                // Si el radio es muy grande, se considera una línea
                if (r > 4000) {
                    dxfFile << "0\nLINE\n8\narc3pkt\n";
                    dxfFile << "10\n" << P0.x << "\n20\n" << P0.y << "\n30\n0.0\n";
                    dxfFile << "11\n" << P1.x << "\n21\n" << P1.y << "\n31\n0.0\n";
                }
                // si el radio es mediano y Las lineas son parecidas en longitud se traza arco
                else if ((r > 1000 || r < 4000) && (LRel < 2 && LRel > 0.5)) {

                    dxfFile << "0\nARC\n8\narc3pkt\n";
                    dxfFile << "10\n" << cx << "\n20\n" << cy << "\n30\n0.0\n";
                    dxfFile << "40\n" << r << "\n";
                    dxfFile << "50\n" << (ang1 * 180.0 / CV_PI) << "\n";
                    dxfFile << "51\n" << (ang2 * 180.0 / CV_PI) << "\n";

                }
                // Si las lineas no son parecidas en longitud o el radio es pequenio, se dejan tal como estan
                else if (r < 1000 || LRel > 2 || LRel < 0.5) {
                    dxfFile << "0\nLINE\n8\narc3pkt\n";
                    dxfFile << "10\n" << P0.x << "\n20\n" << P0.y << "\n30\n0.0\n";
                    dxfFile << "11\n" << P1.x << "\n21\n" << P1.y << "\n31\n0.0\n";
                    }
            }
        }
    }

    // Finalizar sección de entidades y archivo
    dxfFile << "0\nENDSEC\n0\nEOF\n";
    //cierre del archivo (común a todos los metodos)
    dxfFile.close();
}

Contour broken

Here is the .dxf file, you can see it with LibreCAD.

I am working in an App for creating a Contour (Layer ar3pkt) that is a result of fitting ARCs and LINEs in the original Contour (Layer contour). The Layer (approx) is an intermediate step, that you can also see in my code.

It works, but I have the problem that the ARCs are not precise enought. They dont match the Intersection point with the next arc or line precisely. It seems like it works, but if I zoom in, there is a gap between consecutive elements. The gap measures 0.02 CAD units The whole object is 2000 CAD units big.

I added this:

dxfFile << std::fixed << std::setprecision(20);

at the beginning, but also not incrementing the precision.

std::ofstream dxfFile(filename);
dxfFile << std::fixed << std::setprecision(20);
    if (!dxfFile.is_open()) {
        std::cerr << "No se pudo abrir el archivo para escribir: " << filename << std::endl;
        return;
    }

    //Dateikopf DXF
    dxfFile << "0\nSECTION\n2\nHEADER\n0\nENDSEC\n";
    dxfFile << "0\nSECTION\n2\nTABLES\n";
    dxfFile << "0\nTABLE\n2\nLAYER\n";
    dxfFile << "0\nLAYER\n2\ncontour\n70\n0\n62\n1\n";// 
    dxfFile << "0\nLAYER\n2\napprox\n70\n0\n62\n3\n"; // 
    dxfFile << "0\nLAYER\n2\narc3pkt\n70\n0\n62\n7\n"; // 
    dxfFile << "0\nENDTAB\n0\nENDSEC\n";
    dxfFile << "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n";
    dxfFile << "0\nSECTION\n2\nENTITIES\n";

    // Alle Konturen als polyline schreiben
    for (const auto& contour : contours) {
        //glaettung approxPolyDP
            
        if (true)
        {
            std::vector<cv::Point> approx, fittedContour;
            double epsilon = 4;

            dxfFile << "0\nPOLYLINE\n8\ncontour\n66\n1\n70\n1\n";
            for (const auto& point : contour) {
                dxfFile << "0\nVERTEX\n8\ncontour\n10\n" << point.x << "\n20\n" << point.y << "\n30\n0.0\n";
            }
            dxfFile << "0\nSEQEND\n";

            cv::approxPolyDP(contour, approx, epsilon, true); // Glaettung 

            dxfFile << "0\nPOLYLINE\n8\napprox\n66\n1\n70\n1\n";
            for (const auto& point : approx) {
                dxfFile << "0\nVERTEX\n8\napprox\n10\n" << point.x << "\n20\n" << point.y << "\n30\n0.0\n";
            }
            dxfFile << "0\nSEQEND\n";     

            // Geraden und Bogen fitten
            for (size_t i = 0; i < approx.size(); i ++) {
               // Ajustar arco a 3 puntos
               cv::Point2f P0 = approx[i];
               cv::Point2f P1 = approx[(i + 1) % approx.size()];
               cv::Point2f P2 = approx[(i + 2) % approx.size()];

               //Berechnung der relative Laenge
               long double L1 = cv::norm(P1 - P0);
               long double L2 = cv::norm(P2 - P1);
               long double LRel = abs(L1 / L2);

               // Calcular el arco entre 3 puntos
               long double A = P1.x - P0.x;
               long double B = P1.y - P0.y;
               long double C = P2.x - P0.x;
               long double D = P2.y - P0.y;

               long double E = (A * (P0.x + P1.x) + B * (P0.y + P1.y)) / 2.0;
               long double F = (C * (P0.x + P2.x) + D * (P0.y + P2.y)) / 2.0;

               long double det = A * D - B * C;
               if (fabs(det) < 1e-9) continue;

               long  double cx = (D * E - B * F) / det;
               long double cy = (-C * E + A * F) / det;
               long double r = sqrt(pow(cx - P0.x, 2) + pow(cy - P0.y, 2));


               //Solo hay que cambiar esto, para que el angulo solo llege hasta el primerpunto
               long double ang1 = atan2(P0.y - cy, P0.x - cx);
               long double ang2 = atan2(P1.y - cy, P1.x - cx);

               // Asegurar que el arco es el menor posible
               long double anguloDiferencia = ang2 - ang1;
               if (anguloDiferencia < 0) {
                   anguloDiferencia += 2 * CV_PI;
               }
               if (anguloDiferencia > CV_PI) {
                  std::swap(ang1, ang2);
                  ang1 += 2 * CV_PI;
               }

                // Si el radio es muy grande, se considera una línea
                if (r > 4000) {
                    dxfFile << "0\nLINE\n8\narc3pkt\n";
                    dxfFile << "10\n" << P0.x << "\n20\n" << P0.y << "\n30\n0.0\n";
                    dxfFile << "11\n" << P1.x << "\n21\n" << P1.y << "\n31\n0.0\n";
                }
                // si el radio es mediano y Las lineas son parecidas en longitud se traza arco
                else if ((r > 1000 || r < 4000) && (LRel < 2 && LRel > 0.5)) {

                    dxfFile << "0\nARC\n8\narc3pkt\n";
                    dxfFile << "10\n" << cx << "\n20\n" << cy << "\n30\n0.0\n";
                    dxfFile << "40\n" << r << "\n";
                    dxfFile << "50\n" << (ang1 * 180.0 / CV_PI) << "\n";
                    dxfFile << "51\n" << (ang2 * 180.0 / CV_PI) << "\n";

                }
                // Si las lineas no son parecidas en longitud o el radio es pequenio, se dejan tal como estan
                else if (r < 1000 || LRel > 2 || LRel < 0.5) {
                    dxfFile << "0\nLINE\n8\narc3pkt\n";
                    dxfFile << "10\n" << P0.x << "\n20\n" << P0.y << "\n30\n0.0\n";
                    dxfFile << "11\n" << P1.x << "\n21\n" << P1.y << "\n31\n0.0\n";
                    }
            }
        }
    }

    // Finalizar sección de entidades y archivo
    dxfFile << "0\nENDSEC\n0\nEOF\n";
    //cierre del archivo (común a todos los metodos)
    dxfFile.close();
}

Contour broken

Here is the .dxf file, you can see it with LibreCAD.

Share Improve this question edited Mar 27 at 11:29 datenwolf 163k13 gold badges194 silver badges314 bronze badges asked Mar 26 at 19:55 user30015455user30015455 213 bronze badges 2
  • Also see The Computational Geometry Algorithms Library – Richard Critten Commented Mar 26 at 20:20
  • It would help you tremendously to get an answer if this code were a minimal reproducible example. – Drew Dormann Commented Mar 26 at 20:27
Add a comment  | 

1 Answer 1

Reset to default 0

long double LRel = abs(L1 / L2); is suspicious for floating point absolute value.

Try long double LRel = fabs(L1 / L2);.

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1744128404a232568.html

最新回复(0)