1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! # Fornjot CAD Operations
//!
//! This library is part of the [Fornjot] ecosystem. Fornjot is an open-source,
//! code-first CAD application; and collection of libraries that make up the CAD
//! application, but can be used independently.
//!
//! This library is an internal component of Fornjot. It is not relevant to end
//! users that just want to create CAD models.
//!
//! Fornjot models use the [`fj`] crate to define a shape. This crate provides
//! the connection between [`fj`] and the Fornjot kernel. It translates those
//! operations into terms the kernel can understand.
//!
//! [Fornjot]: https://www.fornjot.app/
//! [`fj`]: https://crates.io/crates/fj

#![warn(missing_docs)]

pub mod shape_processor;

mod difference_2d;
mod group;
mod planes;
mod sketch;
mod sweep;
mod transform;

pub use self::planes::Planes;

use fj_interop::debug::DebugInfo;
use fj_kernel::{
    algorithms::validate::{
        Validate, Validated, ValidationConfig, ValidationError,
    },
    objects::{Faces, Sketch},
    stores::Stores,
};
use fj_math::Aabb;

/// Implemented for all operations from the [`fj`] crate
pub trait Shape {
    /// The type that is used for the shape's boundary representation
    type Brep;

    /// Compute the boundary representation of the shape
    fn compute_brep(
        &self,
        config: &ValidationConfig,
        stores: &Stores,
        planes: &Planes,
        debug_info: &mut DebugInfo,
    ) -> Result<Validated<Self::Brep>, ValidationError>;

    /// Access the axis-aligned bounding box of a shape
    ///
    /// If a shape is empty, its [`Aabb`]'s `min` and `max` points must be equal
    /// (but are otherwise not specified).
    fn bounding_volume(&self) -> Aabb<3>;
}

impl Shape for fj::Shape {
    type Brep = Faces;

    fn compute_brep(
        &self,
        config: &ValidationConfig,
        stores: &Stores,
        planes: &Planes,
        debug_info: &mut DebugInfo,
    ) -> Result<Validated<Self::Brep>, ValidationError> {
        match self {
            Self::Shape2d(shape) => shape
                .compute_brep(config, stores, planes, debug_info)?
                .into_inner()
                .into_faces()
                .validate_with_config(config),
            Self::Group(shape) => {
                shape.compute_brep(config, stores, planes, debug_info)
            }
            Self::Sweep(shape) => shape
                .compute_brep(config, stores, planes, debug_info)?
                .into_inner()
                .into_shells()
                .map(|shell| shell.into_faces())
                .reduce(|mut a, b| {
                    a.extend(b);
                    a
                })
                .unwrap_or_default()
                .validate_with_config(config),
            Self::Transform(shape) => {
                shape.compute_brep(config, stores, planes, debug_info)
            }
        }
    }

    fn bounding_volume(&self) -> Aabb<3> {
        match self {
            Self::Shape2d(shape) => shape.bounding_volume(),
            Self::Group(shape) => shape.bounding_volume(),
            Self::Sweep(shape) => shape.bounding_volume(),
            Self::Transform(shape) => shape.bounding_volume(),
        }
    }
}

impl Shape for fj::Shape2d {
    type Brep = Sketch;

    fn compute_brep(
        &self,
        config: &ValidationConfig,
        stores: &Stores,
        planes: &Planes,
        debug_info: &mut DebugInfo,
    ) -> Result<Validated<Self::Brep>, ValidationError> {
        match self {
            Self::Difference(shape) => {
                shape.compute_brep(config, stores, planes, debug_info)
            }
            Self::Sketch(shape) => {
                shape.compute_brep(config, stores, planes, debug_info)
            }
        }
    }

    fn bounding_volume(&self) -> Aabb<3> {
        match self {
            Self::Difference(shape) => shape.bounding_volume(),
            Self::Sketch(shape) => shape.bounding_volume(),
        }
    }
}