Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Back | 3dModel - Collect information about 3d model c/cpp & rust libraries #5

Closed
2 tasks done
Tracked by #3
a-givertzman opened this issue Jul 23, 2024 · 8 comments
Closed
2 tasks done
Tracked by #3
Assignees

Comments

@a-givertzman
Copy link
Owner

a-givertzman commented Jul 23, 2024

  • Choose a crate/lib/tool to work with 3D objects
  • Basic testing of chosen crate/lib/tool
@a-givertzman a-givertzman mentioned this issue Jul 23, 2024
5 tasks
@a-givertzman a-givertzman changed the title Collect information about 3d model c/cpp & rust libraries Back | 3dModel - Collect information about 3d model c/cpp & rust libraries Jul 23, 2024
@novartole
Copy link
Collaborator

Projects overview, not sorted.

name description open source stable age recently updated tech stack CAD kernell import/export .step boolean comment repo
Open CASCADE, occt full-featured CAD kernell LGPL 2.1 v. 7.8.1 12 years last month (06.24) c++ TRUE both TRUE it is massive and has loads of features but written in pure c++ https://git.dev.opencascade.org/gitweb/?p=occt.git;a=summary
opencascade-rs rust bindings to OpenCascade LGPL 2.1 no version tags 17 forks, 87 stars, 52 issues (22 closed), 119 commits 2 years last month (06.24) rust FALSE, but binding to occt kernell both (at least basic scenarios) TRUE wrapper funcs are added on demand that means it doesn't cover all existed API of occt https://github.com/bschwind/opencascade-rs
Truck shape processing kernel Apache 2.0 each service has v. < 1. 48 forks, 900 stars, 25 issues (32 closed), 2k commits 11 contributers 4 years this month (07.24) rust TRUE TRUE TRUE many frameworks already use this kernell (e.g. CADmium) splitted out into services https://github.com/ricosjp/truck
Fornjot early-stage CAD kernel Zero-Clause BSD License v. 0.49.* 109 forks, 1.9k stars 27 issues (306 closed), 15k commits 46 contributers 4 years this month (07.24) rust TRUE FALSE FALSE many features are in early stage (no boolean, no .step format support) https://github.com/hannobraun/fornjot
SINTEF geometry toolkit libs to work with geometry APGL 3.0 no version tags, 39-58 forks 69-173 stars 17 issues (~ 10 closed) 600-1.8k commits 6-11 contributers since 2005 half year (02.24) c, c++ FALSE FALSE, only .iges TRUE good support of many neeeded features, but it uses its own format (.go2) and has free support of .iges only (.step requires licence) https://github.com/SINTEF-Geometry

@novartole
Copy link
Collaborator

novartole commented Aug 12, 2024

Project: Truck.
Topic: Import into .step file.

Sometimes even rather simple models (I used a cube, a cube with one hole (boolean made), a primitive boat shape) give errors.

Known issues/solutions:

  • Error (compilation): Error while deserialize STEP struct: invalid type: Option value, expected a string ...
    Solution: in *.stp file find AXIS2_PLACEMENT_3D and replace $ with '' in its parameter.

  • Error (compilation): Lookup failed for #95 ..., or called Result::unwrap() on an Err value: Error("missing field boundaries", line: 1338, column: 1) ...
    Solution: Wrap the whole output *.json file into boundaries:
    new content gets

{ 
    "boundaries": [ 
        old content
    ] 
}

Some other errors might be output CAD specific (I generated models used Rhino 8). The crate maintainer says that such import is not fully supported yet and was added for demos ( ricosjp/truck#29 (comment) ).

@novartole
Copy link
Collaborator

novartole commented Aug 12, 2024

Project: Truck.
Topic: Object intersection (primitives: cube, sphere, etc.).

OK. Two objects can be OR'ed or AND'ed. One of them should be inverted, for instance, via

truck_topology::solid::Solid::not(&mut self)

@novartole
Copy link
Collaborator

novartole commented Aug 12, 2024

Project: Truck.
Topic: Object intersection (complex models).

I've got a bunch of real boat models exported with different options, included the whole object and chunked into separate parts. After fixes (see known issues/solutions in #5 (comment)) only a few models exported successfully, but with numbers of artefacts.
telegram-cloud-photo-size-2-5307732670891024020-y

@novartole
Copy link
Collaborator

Project: Truck.
Topic: Conclusion.

Truck is a good and ambitious project, but in many use cases its functionality doesn't fit our requirements well. For instance,

For now, there are too many questions and nuances being open regarding this tool (I've mentioned only a few). We decided to stop here, and have a look at a next tool from the table.

@novartole
Copy link
Collaborator

novartole commented Aug 21, 2024

Project: opencascade-rs.
Topic: First impression.

Generally, the project is an adapter from C++ (native language of OCCT) to Rust. It requires manual cover of C++ modules to be called in Rust. Some functionality is already covered by the author, but many cases are not covered yet. The following instruction describes how to extend the wrapper properly.

I've written a few sketches to play with simple and complex objects (the goal of all of them was to find a cross-section by a plane as I did for Truck). It's quite intuitive to develop, and the kernel (OCCT) is well documented (general overview, more technical details of code behind the kernel).

@novartole
Copy link
Collaborator

novartole commented Aug 23, 2024

Project: opencascade-rs.
Topic: Object intersection.

I tested and benchmarked intersection (aka Boolean Common operation) on two models. Read and write from/to STEP works out of box w/o any visual artifacts. Models were created in Rhino 8.0 and (CATIA?). The operation takes about 1sec to complete. Analogue steps in Python console in FreeCAD gives 0.2-0.5 sec. Perhaps, default lack of optimizations affects on that (deeper investigation of this put in backlog).

main.rs

use std::{os::unix::ffi::OsStrExt, path::PathBuf, str::FromStr};

use anyhow::bail;
use clap::{Parser, Subcommand, ValueEnum};
use glam::dvec3;
use opencascade::{
    primitives::{Compound, Edge, IntoShape, Shape},
    workplane::Workplane,
};

fn main() {
    let args = Args::parse();
    let input_model = Shape::read_step(args.input).expect("Failed while reading STEP");
    let output_model = {
        let result = match args.command {
            Cmd::Intersect {
                orientation,
                heigh,
                width,
                depth,
            } => {
                #[cfg(feature = "verbose")]
                let mut instant = std::time::Instant::now();
                let plane = {
                    let (plane, dir) = match orientation {
                        Orientation::Xy => (Workplane::xy(), dvec3(0.0, 0.0, depth)),
                        Orientation::Xz => (Workplane::xz(), dvec3(0.0, depth, 0.0)),
                        Orientation::Yz => (Workplane::yz(), dvec3(0.0, 0.0, depth)),
                    };
                    plane
                        .translated(dir)
                        .rect(width, heigh)
                        .to_face()
                        .into_shape()
                };
                #[cfg(feature = "verbose")]
                {
                    dbg!(instant.elapsed());
                    instant = std::time::Instant::now();
                }
                let result = input_model.intersect(&plane).into_shape();
                #[cfg(feature = "verbose")]
                {
                    dbg!(instant.elapsed());
                }
                result
            }
        };
        if args.join_all {
            Compound::from_shapes([input_model, result]).into_shape()
        } else if args.only_edges {
            Compound::from_shapes(result.edges().map(Edge::into_shape)).into_shape()
        } else {
            result
        }
    };

    output_model
        .write_step(args.output)
        .expect("Failed while writting STEP");
}

#[derive(Parser, Clone)]
/// Examples of use:
///
/// For model hull_centred.step:
///
/// - YZ touches the front holl (print taken time):
///    :cargo run -rF verbose -- hull_centered.step intersect yz 200000.0 200000.0 112000.0
///
/// - XZ from start to end of the hull:
///    :cargo run -r -- hull_centered.step intersect xz 250000.0 250000.0 0.0
///
/// For model ship_for_a.stp:
///
///  - XZ from left to right:
///    :cargo run -- ship_for_a.step intersect xz 100000.0 100000.0 700.0
pub struct Args {
    /// Input file path
    #[clap(value_parser = input_parser)]
    pub input: PathBuf,

    /// Output file path
    #[clap(short, long, default_value = "output.step")]
    pub output: PathBuf,

    /// Join all parts
    #[clap(long, default_value_t = false, group = "view")]
    pub join_all: bool,

    /// Save only edges
    #[clap(long, default_value_t = false, group = "view")]
    pub only_edges: bool,

    /// Commands
    #[command(subcommand)]
    pub command: Cmd,
}

#[derive(ValueEnum, Clone)]
pub enum Orientation {
    Xy,
    Xz,
    Yz,
}

#[derive(Subcommand, Clone)]
pub enum Cmd {
    /// Build plane intersection
    Intersect {
        orientation: Orientation,
        width: f64,
        heigh: f64,
        depth: f64,
    },
}

fn input_parser(arg: &str) -> anyhow::Result<PathBuf> {
    let input = PathBuf::from_str(arg)?;

    if !matches!(
        input.extension().map(OsStrExt::as_bytes),
        Some(b"stp" | b"step")
    ) {
        bail!("Supported output format is .step (.stp).");
    }

    Ok(input)
}

Cargo.toml

[package]
name = "try-occt-rs"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1.0.86"
opencascade = "0.2"

[dependencies.glam]
version = "0.24.2"
features = ["bytemuck"]

[dependencies.clap]
version = "4"
features = ["derive"]

[features]
verbose = []

@novartole
Copy link
Collaborator

opencascade-rs crate has wide functionality and fits well out requirements. It's chosen as the main crate to work with 3D objects. Further investigation is planned in scope of the next task.

novartole added a commit to novartole/opencascade-rs that referenced this issue Nov 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants