Skip to content

Commit

Permalink
Implement basic coloring support for shapes
Browse files Browse the repository at this point in the history
The examples have been extended to demonstrate the coloring of objects.
A few bits and pieces are probably still missing or could be improved
but let's look at those in another step.

Closes hannobraun#291

Signed-off-by: Daniel Egger <[email protected]>
  • Loading branch information
therealprof committed Mar 13, 2022
1 parent 50fa038 commit 62fb197
Show file tree
Hide file tree
Showing 15 changed files with 119 additions and 18 deletions.
64 changes: 60 additions & 4 deletions fj/src/shape_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,59 @@ pub enum Shape2d {
Sketch(Sketch),
}

impl Shape2d {
/// Get the rendering color of the larger object in RGBA
pub fn color (&self) -> [u8; 4] {
match &self
{
Shape2d::Circle(c) => c.color(),
Shape2d::Sketch(s) => s.color(),
Shape2d::Difference(d) => d.color(),
}
}
}


/// A circle
#[derive(Clone, Debug)]
#[repr(C)]
pub struct Circle {
/// The radius of the circle
radius: f64,
// The color of the circle in RGBA
color: [u8; 4],
}

impl Circle {
/// Construct a new circle with a specific radius
pub fn from_radius(radius: f64) -> Self {
Self { radius }
Self {radius, color: [255, 0, 0, 255]}
}

pub fn radius(&self) -> f64 {
self.radius
}

/// Set the rendering color of the circle in RGBA
pub fn with_color(mut self, color: [u8; 4]) -> Self {
self.color = color;
self
}

/// Set the rendering color of the circle in RGBA
pub fn set_color(&mut self, color: [u8; 4]) {
self.color = color;
}

/// Get the rendering color of the circle in RGBA
pub fn color (&self) -> [u8; 4] {
self.color
}
}

impl From<Circle> for Shape {
fn from(shape: Circle) -> Self {
Self::Shape2d(Shape2d::Circle(shape))
Self::Shape2d(shape.into())
}
}

Expand All @@ -62,6 +94,11 @@ impl Difference2d {
Self { a, b }
}

/// Get the rendering color of the larger object in RGBA
pub fn color (&self) -> [u8; 4] {
self.a.color()
}

pub fn a(&self) -> &Shape2d {
&self.a
}
Expand Down Expand Up @@ -100,6 +137,8 @@ pub struct Sketch {
ptr: *mut [f64; 2],
length: usize,
capacity: usize,
// The color of the sketch in RGBA
color: [u8; 4],
}

impl Sketch {
Expand All @@ -118,6 +157,7 @@ impl Sketch {
ptr,
length,
capacity,
color: [255, 0, 0, 255],
}
}

Expand All @@ -141,17 +181,33 @@ impl Sketch {

ret
}

/// Set the rendering color of the sketch in RGBA
pub fn with_color(mut self, color: [u8; 4]) -> Self {
self.color = color;
self
}

/// Set the rendering color of the sketch in RGBA
pub fn set_color(&mut self, color: [u8; 4]) {
self.color = color;
}

/// Get the rendering color of the sketch in RGBA
pub fn color (&self) -> [u8; 4] {
self.color
}
}

impl From<Sketch> for Shape {
fn from(shape: Sketch) -> Self {
Self::Shape2d(Shape2d::Sketch(shape))
Self::Shape2d(shape.into())
}
}

impl From<Sketch> for Shape2d {
fn from(shape: Sketch) -> Self {
Self::Sketch(shape)
Shape2d::Sketch(shape)
}
}

Expand Down
4 changes: 4 additions & 0 deletions fj/src/shape_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ impl Sweep {
pub fn length(&self) -> f64 {
self.length
}

pub fn color(&self) -> [u8; 4] {
self.shape().color()
}
}

impl From<Sweep> for Shape {
Expand Down
2 changes: 1 addition & 1 deletion models/cuboid/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub extern "C" fn model(args: &HashMap<String, String>) -> fj::Shape {
[ x / 2., -y / 2.],
[ x / 2., y / 2.],
[-x / 2., y / 2.],
]);
]).with_color([100,255,0,200]);

let cuboid = fj::Sweep::from_shape_and_length(rectangle.into(), z);

Expand Down
8 changes: 5 additions & 3 deletions models/spacer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,18 @@ pub extern "C" fn model(args: &HashMap<String, String>) -> fj::Shape {
.unwrap_or(&"0.5".to_owned())
.parse()
.unwrap();
let height = args
let height: f64 = args
.get("height")
.unwrap_or(&"1.0".to_owned())
.parse()
.unwrap();

let outer_edge = fj::Circle::from_radius(outer);
let outer_edge =
fj::Circle::from_radius(outer).with_color([0, 0, 255, 255]);
let inner_edge = fj::Circle::from_radius(inner);

let footprint = fj::Difference2d::from_objects(outer_edge.into(), inner_edge.into());
let footprint =
fj::Difference2d::from_objects(outer_edge.into(), inner_edge.into());

let spacer = fj::Sweep::from_shape_and_length(footprint.into(), height);

Expand Down
2 changes: 1 addition & 1 deletion models/star/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub extern "C" fn model(args: &HashMap<String, String>) -> fj::Shape {
inner.push([x / 2., y / 2.]);
}

let outer = fj::Sketch::from_points(outer);
let outer = fj::Sketch::from_points(outer).with_color ([0, 255, 0, 200]);
let inner = fj::Sketch::from_points(inner);

let footprint = fj::Difference2d::from_objects(outer.into(), inner.into());
Expand Down
1 change: 1 addition & 0 deletions src/kernel/algorithms/approximation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ mod tests {
let face = Face::Face {
surface,
cycles: vec![abcd],
color: [255, 0, 0, 255],
};

assert_eq!(
Expand Down
19 changes: 16 additions & 3 deletions src/kernel/algorithms/sweep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
vertices::Vertex,
},
},
math::{Scalar, Transform, Vector},
math::{Scalar, Transform, Triangle, Vector},
};

use super::approximation::Approximation;
Expand All @@ -19,6 +19,7 @@ pub fn sweep_shape(
mut shape_orig: Shape,
path: Vector<3>,
tolerance: Scalar,
color: [u8; 4],
) -> Shape {
let mut shape = shape_orig.clone();

Expand Down Expand Up @@ -96,7 +97,11 @@ pub fn sweep_shape(

shape
.topology()
.add_face(Face::Face { surface, cycles })
.add_face(Face::Face {
surface,
cycles,
color,
})
.unwrap();
}

Expand All @@ -122,12 +127,18 @@ pub fn sweep_shape(
quads.push([v0, v1, v2, v3]);
}

let mut side_face = Vec::new();
let mut side_face: Vec<Triangle<3>> = Vec::new();
for [v0, v1, v2, v3] in quads {
side_face.push([v0, v1, v2].into());
side_face.push([v0, v2, v3].into());
}

// FIXME: We probably want to allow the use of custom colors for the "walls" of the swept
// object.
for s in side_face.iter_mut() {
s.set_color(color);
}

side_faces.push(Face::Triangles(side_face));
}

Expand Down Expand Up @@ -159,6 +170,7 @@ mod tests {
sketch.shape,
Vector::from([0., 0., 1.]),
Scalar::from_f64(0.),
[255, 0, 0, 255],
);

let bottom_face = sketch.face.get().clone();
Expand Down Expand Up @@ -234,6 +246,7 @@ mod tests {
let abc = Face::Face {
surface,
cycles: vec![cycles],
color: [255, 0, 0, 255],
};

let face = shape.topology().add_face(abc).unwrap();
Expand Down
7 changes: 6 additions & 1 deletion src/kernel/algorithms/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ pub fn transform_shape(mut original: Shape, transform: &Transform) -> Shape {

for face in original.topology().faces() {
let face = match face.get().clone() {
Face::Face { cycles, surface } => {
Face::Face {
cycles,
surface,
color,
} => {
let mut cycles_trans = Vec::new();

for cycle in cycles {
Expand Down Expand Up @@ -75,6 +79,7 @@ pub fn transform_shape(mut original: Shape, transform: &Transform) -> Shape {
Face::Face {
cycles: cycles_trans,
surface,
color,
}
}
Face::Triangles(mut triangles) => {
Expand Down
7 changes: 6 additions & 1 deletion src/kernel/shape/topology.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,10 @@ impl Topology<'_> {
/// cycles it refers to are part of the shape). Returns an error, if that is
/// not the case.
pub fn add_face(&mut self, face: Face) -> ValidationResult<Face> {
if let Face::Face { surface, cycles } = &face {
if let Face::Face {
surface, cycles, ..
} = &face
{
let mut missing_surface = None;
let mut missing_cycles = HashSet::new();

Expand Down Expand Up @@ -371,6 +374,7 @@ mod tests {
.add_face(Face::Face {
surface: surface.clone(),
cycles: vec![cycle.clone()],
color: [255, 0, 0, 255],
})
.unwrap_err();
assert!(err.missing_surface(&surface));
Expand All @@ -383,6 +387,7 @@ mod tests {
shape.topology().add_face(Face::Face {
surface,
cycles: vec![cycle],
color: [255, 0, 0, 255],
})?;

Ok(())
Expand Down
6 changes: 5 additions & 1 deletion src/kernel/shapes/circle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ impl ToShape for fj::Circle {
let surface = shape.geometry().add_surface(Surface::x_y_plane());
shape
.topology()
.add_face(Face::Face { cycles, surface })
.add_face(Face::Face {
cycles,
surface,
color: self.color(),
})
.unwrap();

shape
Expand Down
6 changes: 5 additions & 1 deletion src/kernel/shapes/difference_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ impl ToShape for fj::Difference2d {

shape
.topology()
.add_face(Face::Face { cycles, surface })
.add_face(Face::Face {
cycles,
surface,
color: self.color(),
})
.unwrap();

shape
Expand Down
1 change: 1 addition & 0 deletions src/kernel/shapes/sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ impl ToShape for fj::Sketch {
let face = Face::Face {
cycles: shape.topology().cycles().collect(),
surface,
color: self.color(),
};
shape.topology().add_face(face).unwrap();

Expand Down
1 change: 1 addition & 0 deletions src/kernel/shapes/sweep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ impl ToShape for fj::Sweep {
self.shape().to_shape(tolerance, debug_info),
Vector::from([0., 0., self.length()]),
tolerance,
self.color(),
)
}

Expand Down
2 changes: 2 additions & 0 deletions src/kernel/shapes/union.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ fn copy_shape(mut orig: Shape, target: &mut Shape) {
Face::Face {
surface,
cycles: cs,
color,
} => {
target
.topology()
Expand All @@ -112,6 +113,7 @@ fn copy_shape(mut orig: Shape, target: &mut Shape) {
.iter()
.map(|cycle| cycles[cycle].clone())
.collect(),
color: *color,
})
.unwrap();
}
Expand Down
7 changes: 5 additions & 2 deletions src/kernel/topology/faces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub enum Face {
/// It might be less error-prone to specify the edges in surface
/// coordinates.
cycles: Vec<Handle<Cycle>>,
color: [u8; 4],
},

/// The triangles of the face
Expand Down Expand Up @@ -98,7 +99,7 @@ impl Face {
debug_info: &mut DebugInfo,
) {
match self {
Self::Face { surface, .. } => {
Self::Face { surface, color, .. } => {
let approx = Approximation::for_face(self, tolerance);

let points: Vec<_> = approx
Expand Down Expand Up @@ -223,7 +224,9 @@ impl Face {

out.extend(triangles.into_iter().map(|triangle| {
let [a, b, c] = triangle.map(|point| point.canonical());
Triangle::from([a, b, c])
let mut t = Triangle::from([a, b, c]);
t.set_color(*color);
t
}));
}
Self::Triangles(triangles) => out.extend(triangles),
Expand Down

0 comments on commit 62fb197

Please sign in to comment.