Merge pull request #377 from hannobraun/kernel

Extract `fj-kernel` from `fj-app`
This commit is contained in:
Hanno Braun 2022-03-17 18:06:14 +01:00 committed by GitHub
commit 761b1fd865
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 206 additions and 139 deletions

27
Cargo.lock generated
View File

@ -626,23 +626,19 @@ name = "fj-app"
version = "0.5.0"
dependencies = [
"anyhow",
"approx 0.5.1",
"bytemuck",
"clap",
"figment",
"fj",
"fj-debug",
"fj-kernel",
"fj-math",
"futures",
"libloading",
"map-macro",
"nalgebra",
"notify",
"parking_lot 0.12.0",
"parry2d-f64",
"parry3d-f64",
"serde",
"spade",
"thiserror",
"threemf",
"tracing",
@ -659,6 +655,23 @@ dependencies = [
"parry3d-f64",
]
[[package]]
name = "fj-kernel"
version = "0.5.0"
dependencies = [
"anyhow",
"approx 0.5.1",
"fj-debug",
"fj-math",
"map-macro",
"nalgebra",
"parking_lot 0.12.0",
"parry2d-f64",
"parry3d-f64",
"spade",
"thiserror",
]
[[package]]
name = "fj-math"
version = "0.5.0"
@ -1129,9 +1142,9 @@ dependencies = [
[[package]]
name = "map-macro"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3dec3b229449b1a54bd96dc32108086263d6830624e576dc0e6c80e619a0130"
checksum = "9d5b0858fc6e216d2d6222d661021d9b184550acd757fbd80a8f86224069422c"
[[package]]
name = "matchers"

View File

@ -4,6 +4,7 @@ members = [
"fj",
"fj-app",
"fj-debug",
"fj-kernel",
"fj-math",
"models/cuboid",
@ -16,5 +17,6 @@ members = [
default-members = [
"fj-app",
"fj-debug",
"fj-kernel",
"fj-math",
]

View File

@ -13,17 +13,12 @@ categories = ["mathematics", "rendering"]
[dependencies]
anyhow = "1.0.56"
approx = "0.5.1"
bytemuck = "1.8.0"
futures = "0.3.21"
libloading = "0.7.2"
map-macro = "0.2.0"
nalgebra = "0.30.0"
notify = "5.0.0-pre.14"
parking_lot = "0.12.0"
parry2d-f64 = "0.8.0"
parry3d-f64 = "0.8.0"
spade = "2.0.0"
thiserror = "1.0.30"
threemf = "0.2.0"
tracing = "0.1.32"
@ -47,6 +42,10 @@ path = "../fj"
version = "0.5.0"
path = "../fj-debug"
[dependencies.fj-kernel]
version = "0.5.0"
path = "../fj-kernel"
[dependencies.fj-math]
version = "0.5.0"
path = "../fj-math"

View File

@ -1,3 +0,0 @@
pub mod approximation;
pub mod sweep;
pub mod triangulation;

View File

@ -1,9 +0,0 @@
pub mod curves;
pub mod points;
pub mod surfaces;
pub use self::{
curves::{Circle, Curve, Line},
points::Point,
surfaces::Surface,
};

View File

@ -3,9 +3,9 @@ mod camera;
mod config;
mod graphics;
mod input;
mod kernel;
mod mesh;
mod model;
mod operations;
mod window;
use std::collections::HashSet;
@ -30,9 +30,9 @@ use crate::{
camera::Camera,
config::Config,
graphics::{DrawConfig, Renderer},
kernel::shapes::ToShape as _,
mesh::MeshMaker,
model::Model,
operations::ToShape as _,
window::Window,
};

View File

@ -1,11 +1,10 @@
use fj_debug::DebugInfo;
use fj_math::{Aabb, Point, Scalar};
use crate::kernel::{
use fj_kernel::{
geometry::Surface,
shape::Shape,
topology::{edges::Cycle, faces::Face},
topology::{Cycle, Face},
};
use fj_math::{Aabb, Point, Scalar};
use super::ToShape;

View File

@ -1,16 +1,11 @@
use std::collections::HashMap;
use fj_debug::DebugInfo;
use fj_math::{Aabb, Scalar};
use crate::kernel::{
use fj_kernel::{
shape::Shape,
topology::{
edges::{Cycle, Edge},
faces::Face,
vertices::Vertex,
},
topology::{Cycle, Edge, Face, Vertex},
};
use fj_math::{Aabb, Scalar};
use super::ToShape;

View File

@ -1,16 +1,11 @@
use std::collections::HashMap;
use fj_debug::DebugInfo;
use fj_math::{Aabb, Scalar};
use crate::kernel::{
use fj_kernel::{
shape::Shape,
topology::{
edges::{Cycle, Edge},
faces::Face,
vertices::Vertex,
},
topology::{Cycle, Edge, Face, Vertex},
};
use fj_math::{Aabb, Scalar};
use super::ToShape;

View File

@ -6,10 +6,9 @@ pub mod sweep;
pub mod transform;
use fj_debug::DebugInfo;
use fj_kernel::shape::Shape;
use fj_math::{Aabb, Scalar};
use super::shape::Shape;
/// Implemented by all shapes
pub trait ToShape {
/// Compute the boundary representation of the shape

View File

@ -1,11 +1,10 @@
use fj_debug::DebugInfo;
use fj_math::{Aabb, Point, Scalar};
use crate::kernel::{
use fj_kernel::{
geometry::Surface,
shape::Shape,
topology::{edges::Cycle, faces::Face, vertices::Vertex},
topology::{Cycle, Face, Vertex},
};
use fj_math::{Aabb, Point, Scalar};
use super::ToShape;

View File

@ -1,8 +1,7 @@
use fj_debug::DebugInfo;
use fj_kernel::{algorithms::sweep_shape, shape::Shape};
use fj_math::{Aabb, Scalar, Vector};
use crate::kernel::{algorithms::sweep::sweep_shape, shape::Shape};
use super::ToShape;
impl ToShape for fj::Sweep {

View File

@ -1,9 +1,8 @@
use fj_debug::DebugInfo;
use fj_kernel::shape::Shape;
use fj_math::{Aabb, Scalar, Transform};
use parry3d_f64::math::Isometry;
use crate::kernel::shape::Shape;
use super::ToShape;
impl ToShape for fj::Transform {

31
fj-kernel/Cargo.toml Normal file
View File

@ -0,0 +1,31 @@
[package]
name = "fj-kernel"
version = "0.5.0"
edition = "2021"
description = "The world needs another CAD program."
readme = "../README.md"
repository = "https://github.com/hannobraun/fornjot"
license = "0BSD"
keywords = ["cad", "programmatic", "code-cad"]
categories = ["mathematics"]
[dependencies]
anyhow = "1.0.56"
approx = "0.5.1"
map-macro = "0.2.0"
nalgebra = "0.30.0"
parking_lot = "0.12.0"
parry2d-f64 = "0.8.0"
parry3d-f64 = "0.8.0"
spade = "2.0.0"
thiserror = "1.0.30"
[dependencies.fj-debug]
version = "0.5.0"
path = "../fj-debug"
[dependencies.fj-math]
version = "0.5.0"
path = "../fj-math"

View File

@ -2,11 +2,7 @@ use std::collections::HashSet;
use fj_math::{Point, Scalar, Segment};
use crate::kernel::topology::{
edges::{Cycle, Edge},
faces::Face,
vertices::Vertex,
};
use crate::topology::{Cycle, Edge, Face, Vertex};
/// An approximation of an edge, multiple edges, or a face
#[derive(Debug, PartialEq)]
@ -134,10 +130,10 @@ mod tests {
use fj_math::{Point, Scalar, Segment};
use map_macro::set;
use crate::kernel::{
use crate::{
geometry::Surface,
shape::Shape,
topology::{edges::Cycle, faces::Face, vertices::Vertex},
topology::{Cycle, Face, Vertex},
};
use super::{approximate_edge, Approximation};

View File

@ -0,0 +1,13 @@
//! Collection of algorithms that are used by the kernel
//!
//! Algorithmic code is collected in this module, to keep other modules focused
//! on their respective purpose.
mod approximation;
mod sweep;
mod triangulation;
pub use self::{
approximation::Approximation, sweep::sweep_shape,
triangulation::triangulate,
};

View File

@ -2,14 +2,10 @@ use std::collections::HashMap;
use fj_math::{Scalar, Transform, Triangle, Vector};
use crate::kernel::{
geometry::{surfaces::Swept, Surface},
use crate::{
geometry::{Surface, SweptCurve},
shape::{Handle, Shape},
topology::{
edges::{Cycle, Edge},
faces::Face,
vertices::Vertex,
},
topology::{Cycle, Edge, Face, Vertex},
};
use super::approximation::Approximation;
@ -236,11 +232,12 @@ pub fn sweep_shape(
let top_edge =
source_to_top.edges.get(edge_source).unwrap().clone();
let surface =
target.geometry().add_surface(Surface::Swept(Swept {
let surface = target.geometry().add_surface(
Surface::SweptCurve(SweptCurve {
curve: bottom_edge.get().curve(),
path,
}));
}),
);
let cycle = target
.topology()
@ -323,10 +320,10 @@ impl Relation {
mod tests {
use fj_math::{Point, Scalar, Vector};
use crate::kernel::{
geometry::{surfaces::Swept, Surface},
use crate::{
geometry::{Surface, SweptCurve},
shape::{Handle, Shape},
topology::{edges::Cycle, faces::Face, vertices::Vertex},
topology::{Cycle, Face, Vertex},
};
use super::sweep_shape;
@ -407,8 +404,8 @@ mod tests {
})
.unwrap();
let surface = shape.geometry().add_surface(Surface::Swept(
Swept::plane_from_points(
let surface = shape.geometry().add_surface(Surface::SweptCurve(
SweptCurve::plane_from_points(
[a, b, c].map(|vertex| vertex.get().point()),
),
));

View File

@ -2,7 +2,7 @@ use fj_math::Scalar;
use parry2d_f64::utils::point_in_triangle::{corner_direction, Orientation};
use spade::HasPosition;
use crate::kernel::geometry;
use crate::geometry;
/// Create a Delaunay triangulation of all points
pub fn triangulate(

View File

@ -22,6 +22,7 @@ impl Circle {
self.center
}
/// Create a new instance that is transformed by `transform`
#[must_use]
pub fn transform(self, transform: &Transform) -> Self {
let radius = self.radius.to_xyz();
@ -75,6 +76,10 @@ impl Circle {
Vector::from([x, y, Scalar::ZERO])
}
/// Approximate the circle
///
/// `tolerance` specifies how much the approximation is allowed to deviate
/// from the circle.
pub fn approx(&self, tolerance: Scalar, out: &mut Vec<Point<3>>) {
let radius = self.radius.magnitude();

View File

@ -28,7 +28,7 @@ impl Line {
self.origin
}
/// Transform the line
/// Create a new instance that is transformed by `transform`
#[must_use]
pub fn transform(self, transform: &Transform) -> Self {
Self {

View File

@ -1,10 +1,10 @@
mod circle;
mod line;
use fj_math::{Point, Scalar, Transform, Vector};
pub use self::{circle::Circle, line::Line};
use fj_math::{Point, Scalar, Transform, Vector};
/// A one-dimensional shape
///
/// The word "curve" is used as an umbrella term for all one-dimensional shapes,
@ -32,6 +32,7 @@ impl Curve {
}
}
/// Create a new instance that is transformed by `transform`
#[must_use]
pub fn transform(self, transform: &Transform) -> Self {
match self {

View File

@ -0,0 +1,16 @@
//! Geometry objects
//!
//! Simplifying a bit, geometry is responsible for where things are, but now how
//! they are related. The types in this module are referred to by the types in
//! [`crate::topology`], which are responsible for defining how objects are
//! related.
mod curves;
mod points;
mod surfaces;
pub use self::{
curves::{Circle, Curve, Line},
points::Point,
surfaces::{Surface, SweptCurve},
};

View File

@ -1,11 +1,11 @@
pub mod swept;
pub use self::swept::Swept;
pub use self::swept::SweptCurve;
use fj_math::{Point, Transform, Vector};
use nalgebra::vector;
use crate::kernel::geometry;
use crate::geometry;
use super::{Curve, Line};
@ -13,13 +13,13 @@ use super::{Curve, Line};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum Surface {
/// A swept curve
Swept(Swept),
SweptCurve(SweptCurve),
}
impl Surface {
/// Construct a `Surface` that represents the x-y plane
pub fn x_y_plane() -> Self {
Self::Swept(Swept {
Self::SweptCurve(SweptCurve {
curve: Curve::Line(Line {
origin: Point::origin(),
direction: vector![1., 0., 0.].into(),
@ -32,7 +32,9 @@ impl Surface {
#[must_use]
pub fn transform(self, transform: &Transform) -> Self {
match self {
Self::Swept(surface) => Self::Swept(surface.transform(transform)),
Self::SweptCurve(surface) => {
Self::SweptCurve(surface.transform(transform))
}
}
}
@ -42,7 +44,9 @@ impl Surface {
point_3d: Point<3>,
) -> geometry::Point<2> {
let point_2d = match self {
Self::Swept(surface) => surface.point_model_to_surface(&point_3d),
Self::SweptCurve(surface) => {
surface.point_model_to_surface(&point_3d)
}
};
geometry::Point::new(point_2d, point_3d)
@ -51,14 +55,16 @@ impl Surface {
/// Convert a point in surface coordinates to model coordinates
pub fn point_surface_to_model(&self, point: &Point<2>) -> Point<3> {
match self {
Self::Swept(surface) => surface.point_surface_to_model(point),
Self::SweptCurve(surface) => surface.point_surface_to_model(point),
}
}
/// Convert a vector in surface coordinates to model coordinates
pub fn vector_surface_to_model(&self, vector: &Vector<2>) -> Vector<3> {
match self {
Self::Swept(surface) => surface.vector_surface_to_model(vector),
Self::SweptCurve(surface) => {
surface.vector_surface_to_model(vector)
}
}
}
}

View File

@ -1,10 +1,10 @@
use fj_math::{Point, Transform, Vector};
use crate::kernel::geometry::Curve;
use crate::geometry::Curve;
/// A surface that was swept from a curve
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Swept {
pub struct SweptCurve {
/// The curve that this surface was swept from
pub curve: Curve,
@ -12,11 +12,11 @@ pub struct Swept {
pub path: Vector<3>,
}
impl Swept {
impl SweptCurve {
/// Construct a plane from 3 points
#[cfg(test)]
pub fn plane_from_points([a, b, c]: [Point<3>; 3]) -> Self {
use crate::kernel::geometry::Line;
use crate::geometry::Line;
let curve = Curve::Line(Line::from_points([a, b]));
let path = c - a;
@ -57,13 +57,13 @@ mod tests {
use fj_math::{Point, Vector};
use crate::kernel::geometry::{Curve, Line};
use crate::geometry::{Curve, Line};
use super::Swept;
use super::SweptCurve;
#[test]
fn point_model_to_surface() {
let swept = Swept {
let swept = SweptCurve {
curve: Curve::Line(Line {
origin: Point::from([1., 0., 0.]),
direction: Vector::from([0., 2., 0.]),
@ -76,7 +76,7 @@ mod tests {
verify(&swept, Point::from([1., 1.]));
verify(&swept, Point::from([2., 3.]));
fn verify(swept: &Swept, surface_point: Point<2>) {
fn verify(swept: &SweptCurve, surface_point: Point<2>) {
let point = swept.point_surface_to_model(&surface_point);
let result = swept.point_model_to_surface(&point);
@ -86,7 +86,7 @@ mod tests {
#[test]
fn point_surface_to_model() {
let swept = Swept {
let swept = SweptCurve {
curve: Curve::Line(Line {
origin: Point::from([1., 0., 0.]),
direction: Vector::from([0., 2., 0.]),
@ -102,7 +102,7 @@ mod tests {
#[test]
fn vector_surface_to_model() {
let swept = Swept {
let swept = SweptCurve {
curve: Curve::Line(Line {
origin: Point::from([1., 0., 0.]),
direction: Vector::from([0., 2., 0.]),

View File

@ -76,8 +76,9 @@
//! on a per-shape basis. Forcing the user to deal with these issues up-front
//! should lead to less work overall.
#![deny(missing_docs)]
pub mod algorithms;
pub mod geometry;
pub mod shape;
pub mod shapes;
pub mod topology;

View File

@ -1,8 +1,8 @@
use fj_math::{Point, Transform};
use crate::kernel::{
use crate::{
geometry::{Curve, Surface},
topology::faces::Face,
topology::Face,
};
use super::{

View File

@ -5,6 +5,9 @@ use super::{
Store,
};
/// An iterator over geometric or topological objects
///
/// Returned by various methods of the [`Shape`] API.
pub struct Iter<'r, T> {
inner: Inner<'r, T>,
}

View File

@ -1,10 +1,12 @@
pub mod geometry;
pub mod handle;
pub mod iter;
pub mod topology;
pub mod validate;
//! The API used for creating and manipulating shapes
//!
//! See [`Shape`], which is the main entry point to this API.
use fj_math::{Point, Scalar};
mod geometry;
mod handle;
mod iter;
mod topology;
mod validate;
pub use self::{
geometry::Geometry,
@ -14,13 +16,11 @@ pub use self::{
validate::{ValidationError, ValidationResult},
};
use fj_math::{Point, Scalar};
use super::{
geometry::{Curve, Surface},
topology::{
edges::{Cycle, Edge},
faces::Face,
vertices::Vertex,
},
topology::{Cycle, Edge, Face, Vertex},
};
use self::handle::Storage;
@ -109,6 +109,12 @@ impl Shape {
}
}
impl Default for Shape {
fn default() -> Self {
Self::new()
}
}
type Points = Store<Point<3>>;
type Curves = Store<Curve>;
type Surfaces = Store<Surface>;

View File

@ -3,13 +3,9 @@ use std::collections::HashSet;
use fj_debug::DebugInfo;
use fj_math::{Point, Scalar, Triangle, Vector};
use crate::kernel::{
use crate::{
geometry::{Circle, Curve, Line},
topology::{
edges::{Cycle, Edge},
faces::Face,
vertices::Vertex,
},
topology::{Cycle, Edge, Face, Vertex},
};
use super::{
@ -243,6 +239,7 @@ impl Topology<'_> {
Iter::new(self.geometry.faces)
}
/// Triangulate the shape
pub fn triangles(
&self,
tolerance: Scalar,
@ -261,14 +258,10 @@ mod tests {
use fj_math::{Point, Scalar};
use crate::kernel::{
use crate::{
geometry::{Curve, Line, Surface},
shape::{handle::Handle, Shape, ValidationError},
topology::{
edges::{Cycle, Edge},
faces::Face,
vertices::Vertex,
},
topology::{Cycle, Edge, Face, Vertex},
};
const MIN_DISTANCE: f64 = 5e-7;

View File

@ -1,12 +1,8 @@
use std::collections::HashSet;
use crate::kernel::{
use crate::{
geometry::{Curve, Surface},
topology::{
edges::{Cycle, Edge},
faces::Face,
vertices::Vertex,
},
topology::{Cycle, Edge, Face, Vertex},
};
use super::Handle;

View File

@ -1,6 +1,6 @@
use std::hash::{Hash, Hasher};
use crate::kernel::{geometry::Curve, shape::Handle};
use crate::{geometry::Curve, shape::Handle};
use super::vertices::Vertex;
@ -16,6 +16,7 @@ use super::vertices::Vertex;
/// equality of topological objects.
#[derive(Clone, Debug, Eq, Ord, PartialOrd)]
pub struct Cycle {
/// The edges that make up the cycle
pub edges: Vec<Handle<Edge>>,
}

View File

@ -8,8 +8,8 @@ use fj_math::{Aabb, Scalar, Segment, Triangle};
use parry2d_f64::query::{Ray as Ray2, RayCast as _};
use parry3d_f64::query::Ray as Ray3;
use crate::kernel::{
algorithms::{approximation::Approximation, triangulation::triangulate},
use crate::{
algorithms::{triangulate, Approximation},
geometry::Surface,
shape::Handle,
};
@ -43,6 +43,8 @@ pub enum Face {
/// It might be less error-prone to specify the edges in surface
/// coordinates.
cycles: Vec<Handle<Cycle>>,
/// The color of the face
color: [u8; 4],
},
@ -88,6 +90,7 @@ impl Face {
}
}
/// Triangulate the face
pub fn triangles(
&self,
tolerance: Scalar,

View File

@ -1,5 +1,10 @@
//! Topological objects
//!
//! Simplifying a bit, topology is responsible for defining how objects are
//! related, as opposed to geometry, which is responsible for where things are.
//!
//! The types in this module use the types from [`crate::geometry`].
//!
//! # Equality
//!
//! Equality of topological objects is defined in terms of the geometry they
@ -11,6 +16,12 @@
//! definition of identity. Two [`Handle`]s are only considered equal, if they
//! refer to objects in the same memory location.
pub mod edges;
pub mod faces;
pub mod vertices;
mod edges;
mod faces;
mod vertices;
pub use self::{
edges::{Cycle, Edge},
faces::Face,
vertices::Vertex,
};

View File

@ -2,7 +2,7 @@ use std::hash::Hash;
use fj_math::Point;
use crate::kernel::shape::Handle;
use crate::shape::Handle;
/// A vertex
///
@ -19,6 +19,7 @@ use crate::kernel::shape::Handle;
/// equality of topological objects.
#[derive(Clone, Debug, Eq, Ord, PartialOrd)]
pub struct Vertex {
/// The point that defines the location of the vertex
pub point: Handle<Point<3>>,
}