feat(brep): S13-B IGES export + format utilities
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:
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user