{"meta":{"version":"0.9.4","updated":"2026-09-29","namespace":"rf","headers":8,"count":37,"kinds":{"type":"type","struct":"struct","enum":"enum","class":"class","func":"function","method":"method","alias":"alias"},"groups":["Basic types","Result","Mesh","Stats","Repair","Decimator","RidgeExtractor","SelfIntersection","Remesher","io","Progress"]},"symbols":[{"id":"rf-Index","name":"rf::Index","kind":"alias","group":"Basic types","header":"ridgeforge/types.hpp","since":"0.1.0","sig":"using Index = std::uint32_t;","brief":"Vertex and triangle index type. Caps a mesh at 2^31-1 vertices."},{"id":"rf-Scalar","name":"rf::Scalar","kind":"alias","group":"Basic types","header":"ridgeforge/types.hpp","since":"0.1.0","sig":"using Scalar = float;","brief":"Floating scalar; becomes double under -DRF_DOUBLE_PRECISION=ON."},{"id":"rf-Vec3","name":"rf::Vec3","kind":"struct","group":"Basic types","header":"ridgeforge/types.hpp","since":"0.1.0","sig":"struct Vec3 { Scalar x, y, z; };","brief":"Three-component position or direction."},{"id":"rf-Vec2","name":"rf::Vec2","kind":"struct","group":"Basic types","header":"ridgeforge/types.hpp","since":"0.4.0","sig":"struct Vec2 { Scalar u, v; };","brief":"Texture coordinate pair."},{"id":"rf-Tri","name":"rf::Tri","kind":"struct","group":"Basic types","header":"ridgeforge/types.hpp","since":"0.1.0","sig":"struct Tri { Index v[3]; };","brief":"One triangle as three vertex indices."},{"id":"rf-AABB","name":"rf::AABB","kind":"struct","group":"Basic types","header":"ridgeforge/types.hpp","since":"0.3.0","sig":"struct AABB { Vec3 lo, hi; bool empty() const; Vec3 extent() const; };","brief":"Axis-aligned bounding box; empty() is true before any point is added."},{"id":"rf-Status","name":"rf::Status","kind":"enum","group":"Result","header":"ridgeforge/types.hpp","since":"0.2.0","sig":"enum class Status { Ok, FileNotFound, ParseError, UnsupportedFormat, EmptyMesh, NonManifold, InvalidOption, OutOfRange, Cancelled, WriteFailed };","brief":"Ten outcomes; only Ok means success. Carried by every Result."},{"id":"rf-Result","name":"rf::Result<T>","kind":"class","group":"Result","header":"ridgeforge/types.hpp","since":"0.2.0","sig":"template<class T> class Result { explicit operator bool() const noexcept; Status status() const noexcept; const char* message() const noexcept; T& value(); T& operator*(); };","brief":"Error channel used instead of exceptions. Falsy unless status()==Status::Ok.","params":[["operator bool","true exactly when the call succeeded"],["message()","static log string, never null, wording may change in a patch"],["value()","undefined unless bool(*this) is true"]]},{"id":"rf-Mesh","name":"rf::Mesh","kind":"class","group":"Mesh","header":"ridgeforge/mesh.hpp","since":"0.4.0","sig":"class Mesh { std::vector<Vec3> positions; std::vector<Tri> triangles; std::vector<Vec3> normals; std::vector<Vec2> uv; ... };","brief":"Indexed triangle mesh as a plain struct with helper methods; fill the vectors directly if needed.","members":["vertex_count()","triangle_count()","has_normals()","has_uv()","bounds()","clear()","reserve()","validate()"]},{"id":"rf-Mesh-bounds","name":"rf::Mesh::bounds","kind":"method","group":"Mesh","header":"ridgeforge/mesh.hpp","since":"0.4.0","sig":"AABB bounds() const noexcept;","brief":"Recomputed in linear time each call; returns an empty box for an empty mesh, never inverted."},{"id":"rf-Mesh-validate","name":"rf::Mesh::validate","kind":"method","group":"Mesh","header":"ridgeforge/mesh.hpp","since":"0.4.0","sig":"Result<void> validate() const;","brief":"Checks index ranges, non-finite coordinates and attribute sizes. Linear, allocation-free. Call once after building by hand.","returns":"Ok, or OutOfRange / InvalidOption describing the first problem."},{"id":"rf-MeshView","name":"rf::MeshView","kind":"class","group":"Mesh","header":"ridgeforge/mesh.hpp","since":"0.5.0","sig":"MeshView(const Vec3* pos, std::size_t nverts, const Tri* tris, std::size_t ntris) noexcept; MeshView(const Mesh&) noexcept;","brief":"Non-owning read-only view for algorithms that never mutate. Accepted by Stats::of and SelfIntersection::find."},{"id":"rf-Stats","name":"rf::Stats","kind":"struct","group":"Stats","header":"ridgeforge/stats.hpp","since":"0.6.0","sig":"struct Stats { std::size_t vertices, triangles, edges, boundary_loops, components, non_manifold_edges, non_manifold_vertices; int euler_characteristic, genus; bool closed, manifold, oriented; double area, volume; AABB bounds; static Stats of(MeshView); };","brief":"One pass answering most pre-flight questions. genus is -1 and volume 0.0 when their precondition fails."},{"id":"rf-Stats-of","name":"rf::Stats::of","kind":"method","group":"Stats","header":"ridgeforge/stats.hpp","since":"0.6.0","sig":"static Stats of(MeshView);","brief":"Single linear pass over the mesh building one temporary edge table."},{"id":"rf-weld_vertices","name":"rf::Repair::weld_vertices","kind":"func","group":"Repair","header":"ridgeforge/repair.hpp","since":"0.6.0","sig":"std::size_t weld_vertices(Mesh&, Scalar tolerance);","brief":"Merge vertices within tolerance on every axis via a uniform grid. Zero merges exact duplicates only (right for STL).","params":[["mesh","mesh mutated in place"],["tolerance","cell size; 0 = exact duplicates"]],"returns":"count of vertices removed"},{"id":"rf-remove_degenerate","name":"rf::Repair::remove_degenerate","kind":"func","group":"Repair","header":"ridgeforge/repair.hpp","since":"0.6.0","sig":"std::size_t remove_degenerate(Mesh&, Scalar min_area);","brief":"Drop triangles at or below min_area, including those with two equal indices. Scale min_area to your model.","params":[["min_area","area threshold, relative to model scale"]],"returns":"count of triangles removed"},{"id":"rf-remove_duplicate_triangles","name":"rf::Repair::remove_duplicate_triangles","kind":"func","group":"Repair","header":"ridgeforge/repair.hpp","since":"0.6.0","sig":"std::size_t remove_duplicate_triangles(Mesh&);","brief":"Remove triangles that repeat the same index triple.","returns":"count removed"},{"id":"rf-remove_small_components","name":"rf::Repair::remove_small_components","kind":"func","group":"Repair","header":"ridgeforge/repair.hpp","since":"0.6.0","sig":"std::size_t remove_small_components(Mesh&, std::size_t min_triangles);","brief":"Delete connected components below the threshold - the usual way to clear scanner speckle before decimating.","returns":"count of components deleted"},{"id":"rf-orient_consistently","name":"rf::Repair::orient_consistently","kind":"func","group":"Repair","header":"ridgeforge/repair.hpp","since":"0.6.0","sig":"Result<std::size_t> orient_consistently(Mesh&);","brief":"Flood-fill each component and flip faces to agree; for a closed component, flip the whole if signed volume is negative.","returns":"count flipped, or Status::NonManifold when an edge has >2 faces"},{"id":"rf-fill_holes","name":"rf::Repair::fill_holes","kind":"func","group":"Repair","header":"ridgeforge/repair.hpp","since":"0.6.0","sig":"Result<std::size_t> fill_holes(Mesh&, std::size_t max_loop_edges);","brief":"Ear-clip every boundary loop up to max_loop_edges in its best-fit plane; non-planar loops get a centroid fan.","params":[["max_loop_edges","largest loop to close; 0 closes nothing (not an error)"]],"returns":"count of loops closed"},{"id":"rf-DecimateOptions","name":"rf::DecimateOptions","kind":"struct","group":"Decimator","header":"ridgeforge/decimate.hpp","since":"0.7.0","sig":"struct DecimateOptions { std::size_t target_triangles=0; float target_ratio=0; Scalar max_error=0; bool preserve_boundary=true; bool preserve_ridges=false; float ridge_angle_deg=40; float max_aspect_ratio=20; bool allow_topology_change=false; const std::vector<Index>* locked_vertices=nullptr; Progress progress=nullptr; unsigned threads=0; };","brief":"Collapse controls. At least one of target_triangles, target_ratio or max_error must be non-zero or run returns InvalidOption."},{"id":"rf-Decimator","name":"rf::Decimator","kind":"class","group":"Decimator","header":"ridgeforge/decimate.hpp","since":"0.7.0","sig":"explicit Decimator(DecimateOptions opt); Result<DecimateReport> run(Mesh& mesh);","brief":"Quadric-error edge-collapse decimator. Reusable across meshes; no state survives a run."},{"id":"rf-DecimateReport","name":"rf::DecimateReport","kind":"struct","group":"Decimator","header":"ridgeforge/decimate.hpp","since":"0.7.0","sig":"struct DecimateReport { std::size_t collapses, triangles_before, triangles_after; double max_applied_error; bool target_reached; };","brief":"What a run did. target_reached==false with status Ok is normal when locks block the target."},{"id":"rf-RidgeOptions","name":"rf::RidgeOptions","kind":"struct","group":"RidgeExtractor","header":"ridgeforge/ridge.hpp","since":"0.8.0","sig":"struct RidgeOptions { float min_angle_deg=35; float max_angle_deg=175; std::size_t min_edges=4; bool include_boundary=true; unsigned smooth_passes=0; bool split_at_junctions=true; };","brief":"Thresholds for which edges qualify and how chains are cut."},{"id":"rf-RidgeKind","name":"rf::RidgeKind","kind":"enum","group":"RidgeExtractor","header":"ridgeforge/ridge.hpp","since":"0.8.0","sig":"enum class RidgeKind { Ridge, Valley, Boundary };","brief":"Convex, concave or boundary; a chain changing sign is split so no line is half and half."},{"id":"rf-Polyline","name":"rf::Polyline","kind":"struct","group":"RidgeExtractor","header":"ridgeforge/ridge.hpp","since":"0.8.0","sig":"struct Polyline { std::vector<Index> vertices; RidgeKind kind; float mean_angle_deg; bool closed; };","brief":"One ordered chain. closed is true when first and last vertex coincide; the repeat is not stored twice."},{"id":"rf-RidgeExtractor","name":"rf::RidgeExtractor","kind":"class","group":"RidgeExtractor","header":"ridgeforge/ridge.hpp","since":"0.8.0","sig":"explicit RidgeExtractor(RidgeOptions opt); Result<RidgeSet> run(const Mesh& mesh) const;","brief":"Chains sharp edges into ordered ridge/valley polylines rather than an unsorted edge set."},{"id":"rf-SI-FindOptions","name":"rf::SelfIntersection::FindOptions","kind":"struct","group":"SelfIntersection","header":"ridgeforge/selfint.hpp","since":"0.9.0","sig":"struct FindOptions { bool ignore_adjacent=true; std::size_t max_pairs=0; unsigned threads=0; };","brief":"Controls for exact detection; max_pairs=0 finds all."},{"id":"rf-SI-find","name":"rf::SelfIntersection::find","kind":"func","group":"SelfIntersection","header":"ridgeforge/selfint.hpp","since":"0.9.0","sig":"Result<std::vector<TriPair>> find(MeshView, const FindOptions& = {});","brief":"Exact, tolerance-free detection through a bounding-volume hierarchy. Reports a pair iff the two closed triangles share a point.","returns":"list of intersecting triangle-index pairs"},{"id":"rf-SI-resolve","name":"rf::SelfIntersection::resolve","kind":"func","group":"SelfIntersection","header":"ridgeforge/selfint.hpp","since":"0.9.2","sig":"Result<ResolveReport> resolve(Mesh&, const ResolveOptions& = {});","brief":"Experimental. Moves vertices out of contact, else deletes the smaller offending triangle and recloses. Churns on nested shells."},{"id":"rf-RemeshOptions","name":"rf::RemeshOptions","kind":"struct","group":"Remesher","header":"ridgeforge/remesh.hpp","since":"0.9.0","sig":"struct RemeshOptions { Scalar target_edge_length=0; unsigned iterations=5; float feature_angle_deg=40; bool project_to_input=true; bool preserve_boundary=true; Progress progress=nullptr; };","brief":"Isotropic remeshing controls. target_edge_length 0 means the input mean edge length."},{"id":"rf-Remesher","name":"rf::Remesher","kind":"class","group":"Remesher","header":"ridgeforge/remesh.hpp","since":"0.9.0","sig":"explicit Remesher(RemeshOptions opt); Result<void> run(Mesh& mesh);","brief":"Split, collapse, flip and tangential relaxation for a fixed iteration count. Experimental; isotropic only."},{"id":"rf-io-Format","name":"rf::io::Format","kind":"enum","group":"io","header":"ridgeforge/io.hpp","since":"0.5.0","sig":"enum class Format { Auto, Obj, Ply, Stl };","brief":"Chosen by file extension unless passed explicitly."},{"id":"rf-io-WriteOptions","name":"rf::io::WriteOptions","kind":"struct","group":"io","header":"ridgeforge/io.hpp","since":"0.5.0","sig":"struct WriteOptions { Format format=Format::Auto; bool binary=true; int float_digits=7; bool write_normals=false; };","brief":"Output controls; binary is ignored for OBJ."},{"id":"rf-io-read","name":"rf::io::read","kind":"func","group":"io","header":"ridgeforge/io.hpp","since":"0.5.0","sig":"Result<Mesh> read(const std::string& path); Result<Mesh> read(const std::string& path, Format);","brief":"Load OBJ, PLY (ascii+binary) or binary/ascii STL. STL has no vertex sharing, so weld after reading one.","returns":"the loaded Mesh, or a Status describing the failure"},{"id":"rf-io-write","name":"rf::io::write","kind":"func","group":"io","header":"ridgeforge/io.hpp","since":"0.5.0","sig":"Result<void> write(const Mesh&, const std::string& path); Result<void> write(const Mesh&, const std::string& path, const WriteOptions&);","brief":"Write by extension or explicit options. OBJ and PLY carry normals and one UV set; STL carries positions only."},{"id":"rf-Progress","name":"rf::Progress","kind":"alias","group":"Progress","header":"ridgeforge/types.hpp","since":"0.7.0","sig":"using Progress = std::function<bool(float fraction, const char* stage)>;","brief":"Return false to cancel; leaves a valid intermediate mesh and returns Status::Cancelled. Called from the calling thread only."}]}