Fornjot

early-stage b-rep CAD kernel, written in Rust

Fornjot 0.49.0

It's about time for a new release of Fornjot! This one is a bit of a transitionary one, with lots of work that has been started but isn't finished yet. But none the less, there are a few goodies in here.

Let's take a look at the highlights first. A full (curated) changelog is available below.

fj::Instance

fj::Instance serves as the new entry point to the Fornjot API, and you can now easily create an instance of Fornjot by calling fj::Instance::new().

fj-core, the most substantial of Fornjot's libraries, also has a new entry point, fj_core::Core, which is available as a field on fj::Instance.

The following sections have some examples that show off the improved ease of use.

Create a shell from vertices and indices

It's now possible to create a shell by providing a bunch of vertices and indices:

use fj::core::{objects::Shell, operations::build::BuildShell};

let mut fj = fj::Instance::new();

let tetrahedron = Shell::from_vertices_and_indices(
    [[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
    [[2, 1, 0], [0, 1, 3], [1, 2, 3], [2, 0, 3]],
    &mut fj.core,
);

Here's the result:

A tetrahedron

This is not the most convenient way to create a shape, nor the most powerful one, but it does allow you to specify any arbitrary polyhedron. Where the shape is too complex for less general methods, but not yet too complex to get unwieldy, there's a sweet spot for this approach.

Layers

The core of Fornjot's data structure is the object graph, which describes shapes as a graph of interrelated objects (like faces, edges, vertices, and more). Traditionally, this graph has contained all the data necessary to describe a shape. But in this release, I've started to introduce the concept of dedicated layers.

I've already finished extraction color information to a separate presentation layer. This makes it possible to update the color of an object, without having to create a new, modified object.

let mut fj = fj::Instance::new();

let size = 1.;
let cuboid = cuboid::model([size, size, size], &mut fj.core);

cuboid
  .shells().only()
  .faces().first()
  .region()
  .set_color([0., 1., 0.], &mut fj.core);

Here's the result:

A mostly red cube with one green face

This was mostly a test run, and the main effort is still ongoing: Extracting all geometric information from the object graph into a new geometry layer.

The goal is to leave the object graph as a purely topological data structure, while geometry is defined separately from that, referencing the object graph and enriching it with geometric data.

Once this work is finished, I'm hoping to get some nice advantages from that:

This is currently the main focus of my ongoing work, and I hope to have more progress to show soon.

Improved validation infrastructure

Validation is a critical piece of Fornjot, which checks your shapes and points out any problems. In this release, I've started to create a new and improved validation infrastructure. This work is still ongoing, and most validation checks still run on the old infrastructure.

I'm taking this as an opportunity to clean up and document all the validation checks, which is a big win in itself. But the new validation infrastructure also has some inherent advantages over the old one.

1. Validation checks are now types

Whereas before, a validation check was a combination of a method and an error variant, hidden away in a private module, each validation check is now a dedicated type. This makes validation checks more discoverable, and provides a place to document them.

Here's an example from Fornjot's API reference:

Screenshot from Fornjot's API reference, showing the documentation of a validation check

2. Validation checks implement a trait

There already was a validation trait, but it was implemented per-object. With the new trait being implemented per-check, but referencing the object, it shows up in the object's documentation, further aiding discoverability.

Here's how that looks:

Screenshot from Fornjot's API reference, showing a validation check referenced from an object's documentation

3. Easier code sharing

With validation checks no longer organized strictly per-object, it's now easier to share code between similar checks, or even implement the same validation check for multiple types of object.

More flexible exporting

Fornjot can currently export shapes to .3mf, .obj, and .stl files. Before, you had to export the shape to an actual file, but now you can pass any impl io::Write + io::Seek, providing you better flexibility in where the exported data actually goes.

In addition, you can now explicitly choose which format to export to via the respective methods in the fj-export crate, whereas before, the format was chosen automatically based on the file extension.

This work was driven and implemented by contributor @IamTheCarl. Thank you!

Cleanups, fixes, improvements to documentation

In addition to the highlights already mentioned, we have the usual avalanche of small improvements, fixes, and documentation updates. Check out the pull requests linked below, for a full view of what happened!

I'd like to thank all the contributors who helped out with this release. Thank you @nathan-folsom, @brungardtdb, @watana318, @IamTheCarl, and @emka! You're awesome!

Sponsors

Fornjot is supported by @MitchellHansen, @webtrax-oz, @seanjensengrey, @reivilibre, @lthiery, @ahdinosaur, @martindederer, @bollian, @sucaba, and my other awesome sponsors. Thank you!

If you want Fornjot to be sustainable long-term, please consider supporting me too.

Library improvements

Improvements to Fornjot libraries.

fj

fj-core

fj-export

fj-interop

fj-viewer

Other changes

Improvements that are not associated with a specific Fornjot library.