feat(brep): S13-B IGES export + format utilities
CI / Build & Test (push) Failing after 33s
CI / Release Build (push) Failing after 39s

Add IGES v5.3 export for B-Rep models with:
- Entity mapping: Point(116), Line(110), Circular Arc(100),
  B-Spline Curve(126), Plane(108), B-Spline Surface(128),
  Vertex(502), Edge(504), Loop(508), Face(510), Shell(514),
  Manifold Solid B-Rep(186)
- Auto-detection of circular arcs (degree-2 NURBS with
  isosceles control triangle) and planes (1x1 degree surfaces)
- Fixed 80-column IGES format with S/G/D/P/T sections
- Header-only format_utils.h for IGES/STEP number formatting

New files:
- include/vde/foundation/format_utils.h
- include/vde/brep/iges_export.h
- src/brep/iges_export.cpp
- tests/brep/test_iges_export.cpp
This commit is contained in:
茂之钳
2026-07-24 07:34:27 +00:00
parent 092f35c3af
commit 4f75bb8b07
6 changed files with 951 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include "vde/brep/brep.h"
#include <string>
#include <vector>
namespace vde::brep {
/// Export B-Rep bodies to IGES format string (version 5.3)
/// Supports common entity types for maximum compatibility:
/// - Type 116: Point
/// - Type 110: Line
/// - Type 100: Circular Arc
/// - Type 126: Rational B-Spline Curve
/// - Type 108: Plane
/// - Type 128: Rational B-Spline Surface
/// - Type 502: Vertex (B-Rep topology)
/// - Type 504: Edge
/// - Type 508: Loop
/// - Type 510: Face
/// - Type 514: Shell
/// - Type 186: Manifold Solid B-Rep Object
[[nodiscard]] std::string export_iges(const std::vector<BrepModel>& bodies);
/// Export to IGES file
void export_iges_file(const std::string& filepath, const std::vector<BrepModel>& bodies);
} // namespace vde::brep
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include "vde/core/point.h"
#include <string>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdio>
namespace vde::foundation {
/// Format double with adequate precision for CAD (12 significant digits)
inline std::string fmt_double(double v, int precision = 12) {
if (std::isnan(v)) return "0.0";
if (std::isinf(v)) return v > 0 ? "1e30" : "-1e30";
std::ostringstream ss;
ss << std::setprecision(precision) << std::scientific << v;
std::string s = ss.str();
// Ensure always has exponent sign (e.g., "1.0e+00" not "1.0e00")
auto epos = s.find('e');
if (epos != std::string::npos) {
if (epos + 1 < s.size() && s[epos + 1] != '-' && s[epos + 1] != '+') {
s.insert(epos + 1, "+");
}
}
return s;
}
/// Format for IGES: uses D exponent
inline std::string fmt_iges_real(double v) {
auto s = fmt_double(v, 12);
auto pos = s.find('e');
if (pos != std::string::npos) s[pos] = 'D';
return s;
}
/// Format a Point3D as comma-separated reals
inline std::string fmt_point(const core::Point3D& p, bool use_d = false) {
auto fmt = use_d ? fmt_iges_real : fmt_double;
return fmt(p.x()) + "," + fmt(p.y()) + "," + fmt(p.z());
}
/// Pad a string to exactly 72 characters with spaces
inline std::string pad72(const std::string& s) {
std::string result = s;
if (result.size() > 72) result.resize(72);
result.resize(72, ' ');
return result;
}
/// Format an IGES section line: data + section marker (80 columns total)
inline std::string format_iges_line(const std::string& data, char section_char, int seq) {
std::string line = pad72(data);
char seq_buf[9];
std::snprintf(seq_buf, sizeof(seq_buf), "%c%07d", section_char, seq);
line += std::string(seq_buf);
return line + "\n";
}
} // namespace vde::foundation