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.
long double LRel = abs(L1 / L2);
is suspicious for floating point absolute value.
Try long double LRel = fabs(L1 / L2);
.