#include "chijin/src/ffi.rs.h"
#include <cmath>
#include <cstring>
#include <algorithm>
namespace chijin {
std::streambuf::int_type RustReadStreambuf::underflow() {
rust::Slice<uint8_t> slice(
reinterpret_cast<uint8_t*>(buf_), sizeof(buf_));
size_t n = rust_reader_read(reader_, slice);
if (n == 0) return traits_type::eof();
setg(buf_, buf_, buf_ + n);
return traits_type::to_int_type(*gptr());
}
std::streambuf::int_type RustWriteStreambuf::overflow(int_type ch) {
if (ch != traits_type::eof()) {
buf_[pos_++] = static_cast<char>(ch);
if (pos_ >= sizeof(buf_)) {
if (!flush_buf()) return traits_type::eof();
}
}
return ch;
}
std::streamsize RustWriteStreambuf::xsputn(const char* s, std::streamsize count) {
std::streamsize written = 0;
while (written < count) {
std::streamsize space = sizeof(buf_) - pos_;
std::streamsize chunk = std::min(count - written, space);
std::memcpy(buf_ + pos_, s + written, chunk);
pos_ += static_cast<size_t>(chunk);
written += chunk;
if (pos_ >= sizeof(buf_)) {
if (!flush_buf()) return written;
}
}
return written;
}
int RustWriteStreambuf::sync() {
return flush_buf() ? 0 : -1;
}
bool RustWriteStreambuf::flush_buf() {
if (pos_ == 0) return true;
rust::Slice<const uint8_t> slice(
reinterpret_cast<const uint8_t*>(buf_), pos_);
size_t n = rust_writer_write(writer_, slice);
if (n < pos_) return false;
pos_ = 0;
return true;
}
std::unique_ptr<TopoDS_Shape> read_step_stream(RustReader& reader) {
RustReadStreambuf sbuf(reader);
std::istream is(&sbuf);
auto* step_reader = new STEPControl_Reader();
IFSelect_ReturnStatus status = step_reader->ReadStream("stream", is);
if (status != IFSelect_RetDone) {
return nullptr;
}
step_reader->TransferRoots(Message_ProgressRange());
return std::make_unique<TopoDS_Shape>(step_reader->OneShape());
}
std::unique_ptr<TopoDS_Shape> read_brep_bin_stream(RustReader& reader) {
std::string data;
char buf[8192];
for (;;) {
rust::Slice<uint8_t> slice(reinterpret_cast<uint8_t*>(buf), sizeof(buf));
size_t n = rust_reader_read(reader, slice);
if (n == 0) break;
data.append(buf, n);
}
std::istringstream iss(std::move(data));
auto shape = std::make_unique<TopoDS_Shape>();
try {
BinTools::Read(*shape, iss);
} catch (const Standard_Failure&) {
return nullptr;
}
if (shape->IsNull()) {
return nullptr;
}
return shape;
}
bool write_brep_bin_stream(const TopoDS_Shape& shape, RustWriter& writer) {
RustWriteStreambuf sbuf(writer);
std::ostream os(&sbuf);
try {
BinTools::Write(shape, os);
} catch (const Standard_Failure&) {
return false;
}
return os.good();
}
std::unique_ptr<TopoDS_Shape> read_brep_text_stream(RustReader& reader) {
RustReadStreambuf sbuf(reader);
std::istream is(&sbuf);
auto shape = std::make_unique<TopoDS_Shape>();
BRep_Builder builder;
try {
BRepTools::Read(*shape, is, builder);
} catch (const Standard_Failure&) {
return nullptr;
}
if (shape->IsNull()) {
return nullptr;
}
return shape;
}
bool write_brep_text_stream(const TopoDS_Shape& shape, RustWriter& writer) {
RustWriteStreambuf sbuf(writer);
std::ostream os(&sbuf);
try {
BRepTools::Write(shape, os);
} catch (const Standard_Failure&) {
return false;
}
return os.good();
}
std::unique_ptr<TopoDS_Shape> make_half_space(
double ox, double oy, double oz,
double nx, double ny, double nz)
{
gp_Pnt origin(ox, oy, oz);
gp_Dir normal(nx, ny, nz);
gp_Pln plane(origin, normal);
BRepBuilderAPI_MakeFace face_maker(plane);
TopoDS_Face face = face_maker.Face();
double len = std::sqrt(nx*nx + ny*ny + nz*nz);
gp_Pnt ref_point(ox - nx/len, oy - ny/len, oz - nz/len);
BRepPrimAPI_MakeHalfSpace maker(face, ref_point);
return std::make_unique<TopoDS_Shape>(maker.Solid());
}
std::unique_ptr<TopoDS_Shape> make_box(
double x1, double y1, double z1,
double x2, double y2, double z2)
{
double minx = std::min(x1, x2);
double miny = std::min(y1, y2);
double minz = std::min(z1, z2);
double maxx = std::max(x1, x2);
double maxy = std::max(y1, y2);
double maxz = std::max(z1, z2);
gp_Pnt p_min(minx, miny, minz);
double dx = maxx - minx;
double dy = maxy - miny;
double dz = maxz - minz;
BRepPrimAPI_MakeBox maker(p_min, dx, dy, dz);
return std::make_unique<TopoDS_Shape>(maker.Shape());
}
std::unique_ptr<TopoDS_Shape> make_cylinder(
double px, double py, double pz,
double dx, double dy, double dz,
double radius, double height)
{
gp_Pnt center(px, py, pz);
gp_Dir direction(dx, dy, dz);
gp_Ax2 axis(center, direction);
BRepPrimAPI_MakeCylinder maker(axis, radius, height);
return std::make_unique<TopoDS_Shape>(maker.Shape());
}
std::unique_ptr<TopoDS_Shape> make_empty() {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
return std::make_unique<TopoDS_Shape>(compound);
}
std::unique_ptr<TopoDS_Shape> deep_copy(const TopoDS_Shape& shape) {
BRepBuilderAPI_Copy copier(shape, Standard_True, Standard_False);
return std::make_unique<TopoDS_Shape>(copier.Shape());
}
std::unique_ptr<TopoDS_Shape> boolean_fuse(
const TopoDS_Shape& a, const TopoDS_Shape& b)
{
BRepAlgoAPI_Fuse fuse(a, b);
fuse.Build();
if (!fuse.IsDone()) {
return make_empty();
}
BRepBuilderAPI_Copy copier(fuse.Shape(), Standard_True, Standard_False);
return std::make_unique<TopoDS_Shape>(copier.Shape());
}
std::unique_ptr<TopoDS_Shape> boolean_cut(
const TopoDS_Shape& a, const TopoDS_Shape& b)
{
BRepAlgoAPI_Cut cut(a, b);
cut.Build();
if (!cut.IsDone()) {
return make_empty();
}
BRepBuilderAPI_Copy copier(cut.Shape(), Standard_True, Standard_False);
return std::make_unique<TopoDS_Shape>(copier.Shape());
}
std::unique_ptr<TopoDS_Shape> boolean_common(
const TopoDS_Shape& a, const TopoDS_Shape& b)
{
BRepAlgoAPI_Common common(a, b);
common.Build();
if (!common.IsDone()) {
return make_empty();
}
BRepBuilderAPI_Copy copier(common.Shape(), Standard_True, Standard_False);
return std::make_unique<TopoDS_Shape>(copier.Shape());
}
std::unique_ptr<TopoDS_Shape> clean_shape(const TopoDS_Shape& shape) {
ShapeUpgrade_UnifySameDomain unifier(shape, Standard_True, Standard_True, Standard_True);
unifier.AllowInternalEdges(Standard_False);
unifier.Build();
return std::make_unique<TopoDS_Shape>(unifier.Shape());
}
std::unique_ptr<TopoDS_Shape> translate_shape(
const TopoDS_Shape& shape,
double tx, double ty, double tz)
{
gp_Trsf transform;
transform.SetTranslation(gp_Vec(tx, ty, tz));
BRepBuilderAPI_Transform transformer(shape, transform, Standard_True);
return std::make_unique<TopoDS_Shape>(transformer.Shape());
}
bool shape_is_null(const TopoDS_Shape& shape) {
return shape.IsNull();
}
MeshData mesh_shape(const TopoDS_Shape& shape, double tolerance) {
MeshData result;
result.success = false;
BRepMesh_IncrementalMesh mesher(shape, tolerance);
if (!mesher.IsDone()) {
return result;
}
uint32_t global_vertex_offset = 0;
for (TopExp_Explorer explorer(shape, TopAbs_FACE); explorer.More(); explorer.Next()) {
TopoDS_Face face = TopoDS::Face(explorer.Current());
TopLoc_Location location;
Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation(face, location);
if (triangulation.IsNull()) {
continue;
}
int nb_nodes = triangulation->NbNodes();
int nb_triangles = triangulation->NbTriangles();
BRepGProp_Face prop_face(face);
for (int i = 1; i <= nb_nodes; i++) {
gp_Pnt p = triangulation->Node(i);
p.Transform(location.Transformation());
result.vertices.push_back(p.X());
result.vertices.push_back(p.Y());
result.vertices.push_back(p.Z());
}
if (triangulation->HasUVNodes()) {
double u_min = 1e30, u_max = -1e30, v_min = 1e30, v_max = -1e30;
for (int i = 1; i <= nb_nodes; i++) {
gp_Pnt2d uv = triangulation->UVNode(i);
u_min = std::min(u_min, uv.X());
u_max = std::max(u_max, uv.X());
v_min = std::min(v_min, uv.Y());
v_max = std::max(v_max, uv.Y());
}
double u_range = u_max - u_min;
double v_range = v_max - v_min;
if (u_range < 1e-10) u_range = 1.0;
if (v_range < 1e-10) v_range = 1.0;
for (int i = 1; i <= nb_nodes; i++) {
gp_Pnt2d uv = triangulation->UVNode(i);
result.uvs.push_back((uv.X() - u_min) / u_range);
result.uvs.push_back((uv.Y() - v_min) / v_range);
}
} else {
for (int i = 1; i <= nb_nodes; i++) {
result.uvs.push_back(0.0);
result.uvs.push_back(0.0);
}
}
if (!triangulation->HasNormals()) {
triangulation->ComputeNormals();
}
for (int i = 1; i <= nb_nodes; i++) {
gp_Dir normal = triangulation->Normal(i);
if (face.Orientation() == TopAbs_REVERSED) {
result.normals.push_back(-normal.X());
result.normals.push_back(-normal.Y());
result.normals.push_back(-normal.Z());
} else {
result.normals.push_back(normal.X());
result.normals.push_back(normal.Y());
result.normals.push_back(normal.Z());
}
}
bool reversed = (face.Orientation() == TopAbs_REVERSED);
for (int i = 1; i <= nb_triangles; i++) {
const Poly_Triangle& tri = triangulation->Triangle(i);
int n1, n2, n3;
tri.Get(n1, n2, n3);
if (reversed) {
result.indices.push_back(global_vertex_offset + n1 - 1);
result.indices.push_back(global_vertex_offset + n3 - 1);
result.indices.push_back(global_vertex_offset + n2 - 1);
} else {
result.indices.push_back(global_vertex_offset + n1 - 1);
result.indices.push_back(global_vertex_offset + n2 - 1);
result.indices.push_back(global_vertex_offset + n3 - 1);
}
}
global_vertex_offset += nb_nodes;
}
result.success = true;
return result;
}
std::unique_ptr<TopExp_Explorer> explore_faces(const TopoDS_Shape& shape) {
return std::make_unique<TopExp_Explorer>(shape, TopAbs_FACE);
}
std::unique_ptr<TopExp_Explorer> explore_edges(const TopoDS_Shape& shape) {
TopTools_IndexedMapOfShape edgeMap;
TopExp::MapShapes(shape, TopAbs_EDGE, edgeMap);
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
for (int i = 1; i <= edgeMap.Extent(); i++) {
builder.Add(compound, edgeMap(i));
}
return std::make_unique<TopExp_Explorer>(compound, TopAbs_EDGE);
}
bool explorer_more(const TopExp_Explorer& explorer) {
return explorer.More();
}
void explorer_next(TopExp_Explorer& explorer) {
explorer.Next();
}
std::unique_ptr<TopoDS_Face> explorer_current_face(const TopExp_Explorer& explorer) {
return std::make_unique<TopoDS_Face>(TopoDS::Face(explorer.Current()));
}
std::unique_ptr<TopoDS_Edge> explorer_current_edge(const TopExp_Explorer& explorer) {
return std::make_unique<TopoDS_Edge>(TopoDS::Edge(explorer.Current()));
}
void face_center_of_mass(const TopoDS_Face& face,
double& cx, double& cy, double& cz)
{
GProp_GProps props;
BRepGProp::SurfaceProperties(face, props);
gp_Pnt center = props.CentreOfMass();
cx = center.X();
cy = center.Y();
cz = center.Z();
}
void face_normal_at_center(const TopoDS_Face& face,
double& nx, double& ny, double& nz)
{
GProp_GProps props;
BRepGProp::SurfaceProperties(face, props);
gp_Pnt center = props.CentreOfMass();
Handle(Geom_Surface) surface = BRep_Tool::Surface(face);
GeomAPI_ProjectPointOnSurf projector(center, surface);
double u, v;
projector.LowerDistanceParameters(u, v);
BRepGProp_Face gprop_face(face);
gp_Pnt point;
gp_Vec normal;
gprop_face.Normal(u, v, point, normal);
if (normal.Magnitude() > 1e-10) {
normal.Normalize();
}
nx = normal.X();
ny = normal.Y();
nz = normal.Z();
}
std::unique_ptr<TopoDS_Shape> face_extrude(const TopoDS_Face& face,
double dx, double dy, double dz)
{
gp_Vec prism_vec(dx, dy, dz);
BRepPrimAPI_MakePrism maker(face, prism_vec, Standard_False, Standard_True);
return std::make_unique<TopoDS_Shape>(maker.Shape());
}
std::unique_ptr<TopoDS_Shape> face_to_shape(const TopoDS_Face& face) {
return std::make_unique<TopoDS_Shape>(face);
}
ApproxPoints edge_approximation_segments(
const TopoDS_Edge& edge, double tolerance)
{
ApproxPoints result;
result.count = 0;
BRepAdaptor_Curve curve(edge);
GCPnts_TangentialDeflection approx(curve, tolerance, tolerance);
int nb_points = approx.NbPoints();
result.count = static_cast<uint32_t>(nb_points);
for (int i = 1; i <= nb_points; i++) {
gp_Pnt p = approx.Value(i);
result.coords.push_back(p.X());
result.coords.push_back(p.Y());
result.coords.push_back(p.Z());
}
return result;
}
}