diff --git a/doc/architecture/overall_pipeline.md b/doc/architecture/overall_pipeline.md index 4fbc1e8..28539f8 100644 --- a/doc/architecture/overall_pipeline.md +++ b/doc/architecture/overall_pipeline.md @@ -1,69 +1,89 @@ -Draft +# Draft High-level Architecture + + +## Positioning and relation to existing libraries (Nice To Have but maybe to much) +ConformalLab++ is not intended to replace established geometry processing libraries such as CGAL, libigl, or Geometry Central. Instead, it acts as an experiment-friendly pipeline layer on top of existing data structures and algorithms provided by these libraries. + +The project revives the ideas and algorithms of the original ConformalLab by Stefan Sechelmann in a modern C++ setting, making them easier to combine with contemporary mesh libraries (e.g. Geometry Central for intrinsic quantities and operators) and to reuse in new experimental setups. + +In practice, ConformalLab++ focuses on: + ++ a clear, declarative pipeline description for conformal and Möbius-based mesh experiments, + ++ a unified halfedge-based UniversalMesh representation plus optional alternative representations, + +adapters and plugin units that wrap robust external implementations where appropriate (e.g. CGAL-based repair or reconstruction, Geometry Central–style discrete geometry operators, or libigl functionality) instead of reimplementing them. -High-level geometry pipeline -The following diagram sketches the planned high-level geometry pipeline for ConformalLab++. It shows how different input types are funneled through adapter layers into a universal half-edge mesh representation, processed by the core, and then exported or visualized. +## High-level geometry pipeline +The following diagram outlines the planned high-level pipeline for ConformalLab++. It shows the rough division into preprocessing, processing, and postprocessing. In preprocessing, various input types are first converted into a universal representation (half-edge mesh) via adapter layers and any necessary preprocessing steps. From there, they are processed by the various core processors units and then either exported or visualized in postprocessing, with minor optimizations as necessary. -text +```mermaid graph TD - A["INPUT SOURCES"] A1["Explicit
(OBJ, PLY, STL)"] A2["Implicit
(SDF, Formulas)"] A3["Parametric
(NURBS, Curves)"] A4["Procedural
(Noise, L-Sys)"] - - A --> A1 - A --> A2 - A --> A3 - A --> A4 - - A1 --> ADAPTER1["Adapter Layer"] + ADAPTER1["Input Adapter
(Convert to Universal Represenation)"] + PREPROCESSING["Preprocessor
(refined triangulation etc.)"] + EXT["EXTERNAL LIBRARIES
(Plugin System)
- CGAL"] + UNIVERSAL["UNIVERSAL REPRESENTATION FORM
(HalfEdge Mesh Interface)"] + EXPORT_ADAPTER["Export Adapter Layer"] + PROCESSING["PROCESSING CORE LAYER"] + OPT["Optimization
- Decimation
- Denoising
- Remeshing"] + ALGO["Algorithmic
- Boolean Ops
- Smoothing
- Hole Filling"] + OTHER["Other
- Custom Algos
- Transforms
- Filters"] + POSTPROCESSING["POSTPROCESSING
(refined triangulation etc.)"] + EXPORT["Export Formats
- OBJ
- PLY
- STL
- Custom"] + VIZ["Visualization
- OpenGL
- QT
- Screenshot"] +subgraph PRE[PREPROCESSING] + A1 --> ADAPTER1 A2 --> ADAPTER1 A3 --> ADAPTER1 - A4 --> ADAPTER1 - - ADAPTER1 <--> UNIVERSAL["UNIVERSAL REPRESENTATION FORM
(HalfEdge Mesh Interface)
- Vertices
- Halfedges
- Faces"] - - ADAPTER1 <--> EXT["EXTERNAL LIBRARIES
(Plugin System)
- CGAL
- OpenMesh
- PyNoise
- PointCloud Lib"] - + A4 --> ADAPTER1 + PREPROCESSING <-->ADAPTER1 +end EXT <--> UNIVERSAL - - UNIVERSAL --> PROCESSING["PROCESSING CORE"] - - PROCESSING --> OPT["Optimization
- Decimation
- Denoising
- Remeshing"] - PROCESSING --> ALGO["Algorithmic
- Boolean Ops
- Smoothing
- Hole Filling"] - PROCESSING --> OTHER["Other
- Custom Algos
- Transforms
- Filters"] - + UNIVERSAL --> PROCESSING + UNIVERSAL --> EXPORT_ADAPTER + ADAPTER1 <--> EXT + ADAPTER1 <--> UNIVERSAL OPT --> UNIVERSAL ALGO --> UNIVERSAL OTHER --> UNIVERSAL - - UNIVERSAL --> EXPORT_ADAPTER["Export Adapter Layer"] - - EXPORT_ADAPTER --> EXPORT["Export Formats
- OBJ
- PLY
- STL
- Custom"] - EXPORT_ADAPTER --> VIZ["Visualization
- OpenGL
- QT
- Screenshot"] - +subgraph CORE[PROCESSING ] + PROCESSING --> OPT + PROCESSING --> ALGO + PROCESSING --> OTHER +end +subgraph POST[POSTPROCESSING] + EXPORT_ADAPTER <--> POSTPROCESSING + EXPORT_ADAPTER --> EXPORT + EXPORT_ADAPTER --> VIZ +end style UNIVERSAL fill:#90EE90,stroke:#000,stroke-width:3px,color:#000 + style PREPROCESSING fill:#87CEEB,stroke:#000,stroke-width:2px,color:#000 + style POSTPROCESSING fill:#87CEEB,stroke:#000,stroke-width:2px,color:#000 style PROCESSING fill:#87CEEB,stroke:#000,stroke-width:2px,color:#000 style EXT fill:#DDA0DD,stroke:#000,stroke-width:2px,color:#000 style ADAPTER1 fill:#FFB347,stroke:#000,stroke-width:2px,color:#000 style EXPORT_ADAPTER fill:#FFB347,stroke:#000,stroke-width:2px,color:#000 -All external inputs (file-based, implicit, parametric, procedural) are first converted by an adapter layer into a single universal half-edge mesh interface, which is the canonical internal representation used by the preprocessing and processing stages. The processing core operates on this universal representation and can use external libraries via a plugin-like extension layer, while results are passed through an export adapter to file formats or visualization frontends. +``` +All external inputs (file-based, implicit, parametric, procedural) are first converted by an spezfic input adapter into a single universal interface, which is the canonical internal representation used by the processing stages. The processing core units operates on this universal representation and can use external libraries via a plugin-like extension, while results are passed through an export adapter to file formats or visualization frontends. -Three-stage processing pipeline +## Three-stage processing pipeline The geometry processing pipeline in ConformalLab++ is structured into three main stages, all operating on the same universal mesh representation. -Preprocessing - +### Preprocessing Converts all external inputs (files, analytic models, procedural sources) into the canonical half-edge mesh form. Performs optional cleaning and normalization (e.g. fixing degeneracies, rescaling, enforcing orientation). Guarantees that downstream stages see a well-formed, consistent mesh (or fail early with clear errors). -Processing (core processing units) +### Processing (core processing units) Runs one or more core processing units in sequence on the canonical mesh. @@ -71,7 +91,24 @@ Each unit takes a mesh of the same type as input and produces a mesh of the same Examples: remeshing, conformal parameterization, smoothing, boolean operations, experiment-specific transforms. -Postprocessing +Each core processing unit conceptually has the shape UniversalMesh -> UniversalMesh, but units also declare: + ++ Preconditions: requirements on the input mesh (e.g. triangulated, manifold, oriented, specific attributes present). + ++ Capabilities: guarantees on the output mesh (e.g. remains manifold, produces curvature attributes, preserves boundary). + +A simple example: + ++ RemeshingUnit + + + Preconditions: triangulated, manifold, oriented + + + Capabilities: triangulated, manifold, vertex positions modified, edge count changed + +Pipeline composition is valid if, for every adjacent pair of units, the capabilities of the previous unit satisfy the preconditions of the next unit. + + +### Postprocessing Adapts the processed mesh for external consumption: export to file formats, visualization, analysis tools. @@ -81,30 +118,134 @@ Does not change the core topology or semantics of the processed mesh, only its r This structure makes it easy to reason about where data enters, is modified, and leaves the system, and keeps experimental algorithms clearly separated from IO concerns. -Role of the universal mesh representation +## Role of the universal mesh representation The universal mesh representation (a half-edge mesh interface) is the shared contract between all pipeline stages. -Single input/output type +### Single input/output type Every core processing unit exposes the same function shape conceptually: UniversalMesh → UniversalMesh. This allows units to be chained in arbitrary order as long as their preconditions on the mesh are satisfied. -Local, topology-aware access +### Local, topology-aware access The half-edge structure encodes vertices, halfedges, faces, and their adjacency relations, which is essential for typical geometry operations (e.g. local neighborhood queries, traversal, edge flips). Algorithms do not need to know where the mesh came from (file vs. analytic vs. procedural); they only rely on this uniform interface. -Extensibility via attributes +### Extensibility via attributes The universal mesh may carry extensible per-vertex, per-edge, and per-face attributes (e.g. UVs, curvature, experimental scalar fields). Core units can read and write these attributes while still conforming to the same mesh type, enabling complex pipelines without changing the central data structure. + + Because all processing units speak the same “mesh language”, you can build pipelines like: -text +```bash Preprocessing -> RemeshingUnit -> ConformalMapUnit -> ExperimentSpecificFilter -> Export/Postprocessing +``` without changing the basic function signature or the surrounding infrastructure, only by reordering or swapping units. + +## Declarative pipeline descriptions (Nice To Have but maybe to much) +ConformalLab++ optionally supports a lightweight YAML-based description format for experiments. +A pipeline consists of an input adapter, a sequence of steps (core processing units), and an output adapter. Each step can specify params as well as structural constraints via require and provide keys. A pipeline is considered valid if, for every step, all require conditions are satisfied by the accumulated provide and expect constraints of previous steps + +```yaml + +pipeline: + name: basic_conformal + input: + adapter: obj_reader + source: data/bunny.obj + + steps: + - id: clean + unit: repair_soft_clean + params: + mode: soft + require: + representation: UniversalMesh + triangulated: true + provide: + triangulated: true + manifold: null + + - id: param + unit: conformal_parameterization + params: + method: cauchy_riemann + require: + triangulated: true + manifold: true + provide: + attributes_add: [uv] + + output: + adapter: gltf_writer + target: out/bunny.glb + +``` +Each unit may declare a require section describing what it needs from its input (e.g. representation, triangulated, manifold, required attributes) and a provide section describing what it guarantees on its output (e.g. still triangulated, now manifold, adds a uv attribute). Pipelines are considered valid if for every step, the accumulated provide information of all previous steps satisfies the require constraints of the next step. + +### Repair Units (Nice To Have but maybe to much) + +Before entering the core conformal pipeline, input meshes are passed through an explicit preprocessing stage. This stage is responsible for turning “real-world” polygon data (often noisy, inconsistent, or non‑manifold) into a mesh that satisfies the structural requirements of the subsequent units + +ConformalLab++ provides a small set of repair units that can be combined as needed: + ++ removal of (almost) degenerate triangles (needles, caps), + ++ stitching of compatible boundary cycles to close small gaps, + ++ enforcing a consistent face orientation where possible. + +These units are conceptually similar to geometric repair routines in modern polygon mesh processing toolkits + +We distinguish between two typical modes of operation: + ++ Soft cleaning: minimally invasive repairs intended for visualization and quick experiments. Soft cleaning tries to improve mesh quality without significantly altering topology or removing components. + ++ Hard cleaning: more aggressive repairs intended for numerically robust experiments. Hard cleaning may merge vertices, remove tiny components, and modify local topology to enforce manifoldness and consistent orientation when possible. + +## More internal representations (Nice To Have but maybe to much) +ConformalLab++ distinguishes between internal representation spaces that experiments may move between: + ++ UniversalMesh: a halfedge‑based surface mesh representation used for most combinatorial and conformal algorithms. + ++ PointCloud: an unstructured set of sample points, optionally with normals and additional attributes, used for sampling, resampling, and certain reconstruction tasks. + ++ ImplicitField: a scalar field $f: \mathbf{R}^n \rightarrow \mathbf{R}$ +represented on a grid or as a procedural function, used for iso‑surface extraction and robust shape transformations. + +Each space has its own natural algorithms, and dedicated conversion units allow pipelines to move between these representations when needed. + +### Conversion units + +Typical conversion units include: + ++ mesh_to_pointcloud (sampling vertices and surfaces of a UniversalMesh into a PointCloud), + ++ pointcloud_to_mesh (surface reconstruction from point samples), + ++ mesh_to_implicit (rasterizing a UniversalMesh into a signed distance or occupancy field), + ++ implicit_to_mesh (iso‑surface extraction from an ImplicitField). + +These units are modeled as regular processing units in the pipeline but change the underlying representation space instead of just transforming a mesh + +## Attribute behaviour under topology changes (Nice To Have but maybe to much) + +ConformalLab++ treats attributes as first-class data attached to mesh entities (vertices, edges, faces, halfedges). When topology changes, attributes are updated according to simple, explicit rules: + ++ Vertex splits / edge splits: attributes on newly created vertices or edges are initialized by interpolation of the incident elements (e.g. linear interpolation of scalar fields along an edge). + ++ Edge collapse: attributes on the surviving vertex are computed from the incident vertices, typically by a convex combination or area‑weighted average for scalar quantities. + ++ Face operations (flip, subdivision): face attributes are either propagated (for categorical data) or interpolated (for scalar data) to new faces. + +By default, ConformalLab++ uses linear interpolation for scalar attributes and nearest‑neighbour propagation for discrete or categorical attributes; units may override these policies where necessary + +