Skip to content

Commit a27899f

Browse files
committed
refactor: remove unneeded generics, use more builders
This change removes the need for generic path metadata from shapes. raydeon's Materials allow associating an arbitrary `usize`, which can be used to accomplish the same thing via a lookup table after rendering. Removing the trait bounds makes it easier to maintain the library. This change also introduces the builder pattern to most of raydeon's shape types.
1 parent df32410 commit a27899f

File tree

21 files changed

+448
-493
lines changed

21 files changed

+448
-493
lines changed

README.md

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,27 @@ fn main() {
3535

3636
let scene = Scene::new()
3737
.geometry(vec![
38-
Arc::new(AxisAlignedCuboid::tagged(
39-
(-1.0, -1.0, -1.0),
40-
(1.0, 1.0, 1.0),
41-
Material::new(3.0, 2.0, 2.0, 0),
42-
)),
43-
Arc::new(AxisAlignedCuboid::tagged(
44-
(1.8, -1.0, -1.0),
45-
(3.8, 1.0, 1.0),
46-
Material::new(2.0, 2.0, 2.0, 0),
47-
)),
48-
Arc::new(AxisAlignedCuboid::tagged(
49-
(-1.4, 1.8, -1.0),
50-
(0.6, 3.8, 1.0),
51-
Material::new(3.0, 2.0, 2.0, 0),
52-
)),
38+
Arc::new(
39+
AxisAlignedCuboid::new()
40+
.min((-1.0, -1.0, -1.0))
41+
.max((1.0, 1.0, 1.0))
42+
.material(Material::new(3.0, 2.0, 2.0, 0))
43+
.build(),
44+
),
45+
Arc::new(
46+
AxisAlignedCuboid::new()
47+
.min((1.8, -1.0, -1.0))
48+
.max((3.8, 1.0, 1.0))
49+
.material(Material::new(2.0, 2.0, 2.0, 0))
50+
.build(),
51+
),
52+
Arc::new(
53+
AxisAlignedCuboid::new()
54+
.min((-1.4, 1.8, -1.0))
55+
.max((0.6, 3.8, 1.0))
56+
.material(Material::new(3.0, 2.0, 2.0, 0))
57+
.build(),
58+
),
5359
])
5460
.lighting(
5561
SceneLighting::new()

pyraydeon/src/scene.rs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::sync::Arc;
22

33
use numpy::{Ix1, PyArray, PyReadonlyArray1};
44
use pyo3::prelude::*;
5-
use raydeon::{SceneLighting, WorldSpace};
5+
use raydeon::SceneLighting;
66

77
use crate::light::PointLight;
88
use crate::linear::{ArbitrarySpace, Point2, Point3, Vec3};
@@ -108,7 +108,7 @@ impl Camera {
108108

109109
#[pyclass(frozen)]
110110
pub(crate) struct Scene {
111-
scene: Arc<raydeon::Scene<raydeon::Material>>,
111+
scene: Arc<raydeon::Scene>,
112112
}
113113

114114
#[pymethods]
@@ -123,16 +123,15 @@ impl Scene {
123123
) -> PyResult<Self> {
124124
let geometry = geometry.unwrap_or_default();
125125
let lights = lights.unwrap_or_default();
126-
let geometry: Vec<Arc<dyn raydeon::Shape<WorldSpace, raydeon::material::Material>>> =
127-
geometry
128-
.into_iter()
129-
.map(|g| {
130-
let geom: Py<Geometry> = g.extract(py)?;
131-
let raydeon_shape = geom.borrow(py);
132-
let raydeon_shape = raydeon_shape.geometry(g);
133-
Ok(raydeon_shape)
134-
})
135-
.collect::<PyResult<_>>()?;
126+
let geometry: Vec<Arc<dyn raydeon::Shape>> = geometry
127+
.into_iter()
128+
.map(|g| {
129+
let geom: Py<Geometry> = g.extract(py)?;
130+
let raydeon_shape = geom.borrow(py);
131+
let raydeon_shape = raydeon_shape.geometry(g);
132+
Ok(raydeon_shape)
133+
})
134+
.collect::<PyResult<_>>()?;
136135
let lights: Vec<Arc<dyn raydeon::Light>> = lights
137136
.into_iter()
138137
.map(|l| Arc::new(l.0) as Arc<dyn raydeon::lights::Light>)
@@ -216,7 +215,7 @@ impl LineSegment2D {
216215
}
217216
}
218217

219-
pywrap!(LineSegment3D, raydeon::path::LineSegment3D<ArbitrarySpace, raydeon::material::Material>);
218+
pywrap!(LineSegment3D, raydeon::path::LineSegment3D<ArbitrarySpace>);
220219

221220
#[pymethods]
222221
impl LineSegment3D {
@@ -229,12 +228,14 @@ impl LineSegment3D {
229228
) -> PyResult<Self> {
230229
let p1 = Point3::try_from(p1)?;
231230
let p2 = Point3::try_from(p2)?;
232-
Ok(raydeon::path::LineSegment3D::tagged(
233-
p1.cast_unit(),
234-
p2.cast_unit(),
235-
material.unwrap_or_default().0,
231+
Ok(
232+
raydeon::path::LineSegment3D::new(
233+
p1.cast_unit(),
234+
p2.cast_unit(),
235+
material.map(|i| i.0),
236+
)
237+
.into(),
236238
)
237-
.into())
238239
}
239240

240241
#[getter]

pyraydeon/src/shapes/mod.rs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,9 @@ use crate::material::Material;
1212
use crate::ray::{HitData, Ray, AABB3};
1313
use crate::scene::{Camera, LineSegment3D};
1414

15-
type RMaterial = raydeon::material::Material;
16-
1715
#[derive(Debug)]
1816
enum InnerGeometry {
19-
Native(Arc<dyn raydeon::Shape<WorldSpace, RMaterial>>),
17+
Native(Arc<dyn raydeon::Shape>),
2018
Py,
2119
}
2220

@@ -27,7 +25,7 @@ pub(crate) struct Geometry {
2725
}
2826

2927
impl Geometry {
30-
pub(crate) fn native(geom: Arc<dyn raydeon::Shape<WorldSpace, RMaterial>>) -> Self {
28+
pub(crate) fn native(geom: Arc<dyn raydeon::Shape>) -> Self {
3129
let geom = InnerGeometry::Native(geom);
3230
Self { geom }
3331
}
@@ -37,7 +35,7 @@ impl Geometry {
3735
Self { geom }
3836
}
3937

40-
pub(crate) fn geometry(&self, obj: PyObject) -> Arc<dyn raydeon::Shape<WorldSpace, RMaterial>> {
38+
pub(crate) fn geometry(&self, obj: PyObject) -> Arc<dyn raydeon::Shape> {
4139
match &self.geom {
4240
InnerGeometry::Native(ref geom) => Arc::clone(geom),
4341
InnerGeometry::Py => Arc::new(PythonGeometry::new(obj, PythonGeometryKind::Draw)),
@@ -90,7 +88,7 @@ impl Geometry {
9088

9189
#[derive(Debug)]
9290
enum InnerCollisionGeometry {
93-
Native(Arc<dyn raydeon::CollisionGeometry<WorldSpace>>),
91+
Native(Arc<dyn raydeon::CollisionGeometry>),
9492
Py,
9593
}
9694

@@ -101,7 +99,7 @@ pub(crate) struct CollisionGeometry {
10199
}
102100

103101
impl CollisionGeometry {
104-
pub(crate) fn native(geom: Arc<dyn raydeon::CollisionGeometry<WorldSpace>>) -> Self {
102+
pub(crate) fn native(geom: Arc<dyn raydeon::CollisionGeometry>) -> Self {
105103
let geom = InnerCollisionGeometry::Native(geom);
106104
Self { geom }
107105
}
@@ -176,8 +174,8 @@ impl PythonGeometry {
176174
}
177175
}
178176

179-
impl raydeon::Shape<WorldSpace, raydeon::material::Material> for PythonGeometry {
180-
fn collision_geometry(&self) -> Option<Vec<Arc<dyn raydeon::CollisionGeometry<WorldSpace>>>> {
177+
impl raydeon::Shape for PythonGeometry {
178+
fn collision_geometry(&self) -> Option<Vec<Arc<dyn raydeon::CollisionGeometry>>> {
181179
let collision_geometry: Option<_> = Python::with_gil(|py| {
182180
let inner = self.slf.bind(py);
183181
let call_result = inner.call_method1("collision_geometry", ()).ok()?;
@@ -189,7 +187,7 @@ impl raydeon::Shape<WorldSpace, raydeon::material::Material> for PythonGeometry
189187
.map(|obj| {
190188
Ok(
191189
Arc::new(PythonGeometry::as_collision_geometry(obj?.into_py(py)))
192-
as Arc<dyn raydeon::CollisionGeometry<WorldSpace>>,
190+
as Arc<dyn raydeon::CollisionGeometry>,
193191
)
194192
})
195193
.collect::<PyResult<_>>()
@@ -200,10 +198,7 @@ impl raydeon::Shape<WorldSpace, raydeon::material::Material> for PythonGeometry
200198
collision_geometry
201199
}
202200

203-
fn paths(
204-
&self,
205-
cam: &raydeon::Camera,
206-
) -> Vec<raydeon::path::LineSegment3D<WorldSpace, raydeon::material::Material>> {
201+
fn paths(&self, cam: &raydeon::Camera) -> Vec<raydeon::path::LineSegment3D<WorldSpace>> {
207202
let segments: Option<_> = Python::with_gil(|py| {
208203
let inner = self.slf.bind(py);
209204
let cam = Camera::from(cam.clone());
@@ -236,7 +231,7 @@ impl raydeon::Shape<WorldSpace, raydeon::material::Material> for PythonGeometry
236231
}
237232
}
238233

239-
impl raydeon::CollisionGeometry<WorldSpace> for PythonGeometry {
234+
impl raydeon::CollisionGeometry for PythonGeometry {
240235
fn hit_by(&self, ray: &raydeon::Ray) -> Option<raydeon::HitData> {
241236
if let PythonGeometryKind::Collision { aabb: Some(aabb) } = &self.kind {
242237
raydeon::shapes::AxisAlignedCuboid::from(aabb.0.cast_unit()).hit_by(ray)?;

pyraydeon/src/shapes/primitive.rs

Lines changed: 55 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,21 @@ use crate::material::Material;
44
use numpy::{Ix1, PyArray, PyArrayLike1, PyArrayLike2};
55
use pyo3::exceptions::PyIndexError;
66
use pyo3::prelude::*;
7-
use raydeon::WorldSpace;
87
use std::sync::Arc;
98

10-
type RMaterial = raydeon::material::Material;
11-
129
#[pyclass(frozen, extends=Geometry, subclass)]
13-
pub(crate) struct AxisAlignedCuboid(pub(crate) Arc<raydeon::shapes::AxisAlignedCuboid<RMaterial>>);
10+
pub(crate) struct AxisAlignedCuboid(pub(crate) Arc<raydeon::shapes::AxisAlignedCuboid>);
1411

1512
impl ::std::ops::Deref for AxisAlignedCuboid {
16-
type Target = Arc<raydeon::shapes::AxisAlignedCuboid<RMaterial>>;
13+
type Target = Arc<raydeon::shapes::AxisAlignedCuboid>;
1714

1815
fn deref(&self) -> &Self::Target {
1916
&self.0
2017
}
2118
}
2219

23-
impl From<Arc<raydeon::shapes::AxisAlignedCuboid<RMaterial>>> for AxisAlignedCuboid {
24-
fn from(value: Arc<raydeon::shapes::AxisAlignedCuboid<RMaterial>>) -> Self {
20+
impl From<Arc<raydeon::shapes::AxisAlignedCuboid>> for AxisAlignedCuboid {
21+
fn from(value: Arc<raydeon::shapes::AxisAlignedCuboid>) -> Self {
2522
Self(value)
2623
}
2724
}
@@ -38,32 +35,32 @@ impl AxisAlignedCuboid {
3835
let min: Vec3 = min.try_into()?;
3936
let max: Vec3 = max.try_into()?;
4037

41-
let shape = Arc::new(raydeon::shapes::AxisAlignedCuboid::tagged(
42-
min.cast_unit(),
43-
max.cast_unit(),
44-
material.unwrap_or_default().0,
45-
));
46-
let geom =
47-
Geometry::native(Arc::clone(&shape)
48-
as Arc<dyn raydeon::Shape<WorldSpace, raydeon::material::Material>>);
38+
let shape = Arc::new(
39+
raydeon::shapes::AxisAlignedCuboid::new()
40+
.min(min.cast_unit())
41+
.max(max.cast_unit())
42+
.material(material.map(|m| m.0).unwrap_or_default())
43+
.build(),
44+
);
45+
let geom = Geometry::native(Arc::clone(&shape) as Arc<dyn raydeon::Shape>);
4946

5047
Ok((Self(shape), geom))
5148
}
5249
}
5350

5451
#[pyclass(frozen, extends=Geometry, subclass)]
55-
pub(crate) struct Tri(pub(crate) Arc<raydeon::shapes::Triangle<RMaterial>>);
52+
pub(crate) struct Tri(pub(crate) Arc<raydeon::shapes::Triangle>);
5653

5754
impl ::std::ops::Deref for Tri {
58-
type Target = Arc<raydeon::shapes::Triangle<RMaterial>>;
55+
type Target = Arc<raydeon::shapes::Triangle>;
5956

6057
fn deref(&self) -> &Self::Target {
6158
&self.0
6259
}
6360
}
6461

65-
impl From<Arc<raydeon::shapes::Triangle<RMaterial>>> for Tri {
66-
fn from(value: Arc<raydeon::shapes::Triangle<RMaterial>>) -> Self {
62+
impl From<Arc<raydeon::shapes::Triangle>> for Tri {
63+
fn from(value: Arc<raydeon::shapes::Triangle>) -> Self {
6764
Self(value)
6865
}
6966
}
@@ -82,14 +79,15 @@ impl Tri {
8279
let p2: Point3 = p2.try_into()?;
8380
let p3: Point3 = p3.try_into()?;
8481

85-
let shape = Arc::new(raydeon::shapes::Triangle::tagged(
86-
p1.cast_unit(),
87-
p2.cast_unit(),
88-
p3.cast_unit(),
89-
material.unwrap_or_default().0,
90-
));
91-
let geom =
92-
Geometry::native(Arc::clone(&shape) as Arc<dyn raydeon::Shape<WorldSpace, RMaterial>>);
82+
let shape = Arc::new(
83+
raydeon::shapes::Triangle::new()
84+
.v0(p1.cast_unit())
85+
.v1(p2.cast_unit())
86+
.v2(p3.cast_unit())
87+
.material(material.map(|m| m.0).unwrap_or_default())
88+
.build(),
89+
);
90+
let geom = Geometry::native(Arc::clone(&shape) as Arc<dyn raydeon::Shape>);
9391
Ok((Self(shape), geom))
9492
}
9593
}
@@ -121,13 +119,14 @@ impl Plane {
121119
let point: Point3 = point.try_into()?;
122120
let normal: Vec3 = normal.try_into()?;
123121

124-
let shape = Arc::new(raydeon::shapes::Plane::new(
125-
point.0.cast_unit(),
126-
normal.0.cast_unit(),
127-
));
128-
let geom = CollisionGeometry::native(
129-
Arc::clone(&shape) as Arc<dyn raydeon::CollisionGeometry<WorldSpace>>
122+
let shape = Arc::new(
123+
raydeon::shapes::Plane::new()
124+
.point(point.0.cast_unit())
125+
.normal(normal.0.cast_unit())
126+
.build(),
130127
);
128+
let geom =
129+
CollisionGeometry::native(Arc::clone(&shape) as Arc<dyn raydeon::CollisionGeometry>);
131130
Ok((Self(shape), geom))
132131
}
133132

@@ -162,13 +161,17 @@ impl From<Arc<raydeon::shapes::Sphere>> for Sphere {
162161
#[pymethods]
163162
impl Sphere {
164163
#[new]
165-
fn new(point: &Bound<'_, PyAny>, radius: f64) -> PyResult<(Self, CollisionGeometry)> {
166-
let point: Point3 = point.try_into()?;
167-
168-
let shape = Arc::new(raydeon::shapes::Sphere::new(point.0.cast_unit(), radius));
169-
let geom = CollisionGeometry::native(
170-
Arc::clone(&shape) as Arc<dyn raydeon::CollisionGeometry<WorldSpace>>
164+
fn new(center: &Bound<'_, PyAny>, radius: f64) -> PyResult<(Self, CollisionGeometry)> {
165+
let center: Point3 = center.try_into()?;
166+
167+
let shape = Arc::new(
168+
raydeon::shapes::Sphere::new()
169+
.center(center.0.cast_unit())
170+
.radius(radius)
171+
.build(),
171172
);
173+
let geom =
174+
CollisionGeometry::native(Arc::clone(&shape) as Arc<dyn raydeon::CollisionGeometry>);
172175
Ok((Self(shape), geom))
173176
}
174177

@@ -184,18 +187,18 @@ impl Sphere {
184187
}
185188

186189
#[pyclass(frozen, extends=Geometry, subclass)]
187-
pub(crate) struct Quad(pub(crate) Arc<raydeon::shapes::Quad<RMaterial>>);
190+
pub(crate) struct Quad(pub(crate) Arc<raydeon::shapes::Quad>);
188191

189192
impl ::std::ops::Deref for Quad {
190-
type Target = Arc<raydeon::shapes::Quad<RMaterial>>;
193+
type Target = Arc<raydeon::shapes::Quad>;
191194

192195
fn deref(&self) -> &Self::Target {
193196
&self.0
194197
}
195198
}
196199

197-
impl From<Arc<raydeon::shapes::Quad<RMaterial>>> for Quad {
198-
fn from(value: Arc<raydeon::shapes::Quad<RMaterial>>) -> Self {
200+
impl From<Arc<raydeon::shapes::Quad>> for Quad {
201+
fn from(value: Arc<raydeon::shapes::Quad>) -> Self {
199202
Self(value)
200203
}
201204
}
@@ -241,14 +244,15 @@ impl Quad {
241244
})
242245
.map(|dims| [dims[0], dims[1]])?;
243246

244-
let shape = Arc::new(raydeon::shapes::Quad::tagged(
245-
origin.0.cast_unit(),
246-
basis,
247-
dims,
248-
material.unwrap_or_default().0,
249-
));
250-
let geom =
251-
Geometry::native(Arc::clone(&shape) as Arc<dyn raydeon::Shape<WorldSpace, RMaterial>>);
247+
let shape = Arc::new(
248+
raydeon::shapes::Quad::new()
249+
.origin(origin.0.cast_unit())
250+
.basis(basis)
251+
.dims(dims)
252+
.material(material.map(|m| m.0).unwrap_or_default())
253+
.build(),
254+
);
255+
let geom = Geometry::native(Arc::clone(&shape) as Arc<dyn raydeon::Shape>);
252256
Ok((Self(shape), geom))
253257
}
254258
}

0 commit comments

Comments
 (0)