Skip to content
Snippets Groups Projects
Commit 0357287b authored by Udo Eisenbarth's avatar Udo Eisenbarth :speech_balloon:
Browse files

Improve "add" functions for OpticScenery & OpticNode

parent 5deb892c
No related branches found
No related tags found
No related merge requests found
use opossum::nodes::NodeDummy;
use opossum::optic_node::OpticNode;
use opossum::optic_scenery::OpticScenery;
use std::fs::File;
......@@ -11,8 +10,8 @@ fn main() {
scenery.set_description("OpticScenery demo".into());
println!("default opticscenery: {:?}", scenery);
println!("export to `dot` format: {}", scenery.to_dot());
let node1 = scenery.add_node(OpticNode::new("my optic", Box::new(NodeDummy)));
let node2 = scenery.add_node(OpticNode::new("my other optic", Box::new(NodeDummy)));
let node1 = scenery.add_element("my optic", NodeDummy);
let node2 = scenery.add_element("my other optic", NodeDummy);
if let Ok(_) = scenery.connect_nodes(node1, node2) {
let path = "graph.dot";
let mut output = File::create(path).unwrap();
......
......@@ -8,25 +8,25 @@ use std::io::Write;
fn main() {
let mut scenery = OpticScenery::new();
scenery.set_description("PreAmp Doublepass section".into());
let n1 = scenery.add_node(OpticNode::new("TFP", Box::new(NodeDummy)));
let n2 = scenery.add_node(OpticNode::new("19mm amp", Box::new(NodeDummy)));
let n3 = scenery.add_node(OpticNode::new("Faraday", Box::new(NodeDummy)));
let n4 = scenery.add_node(OpticNode::new("0° mirror", Box::new(NodeDummy)));
let n1 = scenery.add_element("TFP", NodeDummy);
let n2 = scenery.add_element("19mm amp", NodeDummy);
let n3 = scenery.add_element("Faraday", NodeDummy);
let n4 = scenery.add_element("0° mirror", NodeDummy);
// let ref_node= NodeReference::new(scenery.node(n1));
// let n1r=scenery.add_node(OpticNode::new("ref", Box::new(ref_node)));
// let n1r=scenery.add_node("ref", ref_node);
let mut node= OpticNode::new("Faraday", Box::new(NodeDummy));
let mut node = OpticNode::new("Faraday", NodeDummy);
node.set_inverted(true);
let n3i=scenery.add_node(node);
let n3i = scenery.add_node(node);
let mut node= OpticNode::new("19mm amp", Box::new(NodeDummy));
let mut node = OpticNode::new("19mm amp", NodeDummy);
node.set_inverted(true);
let n2i=scenery.add_node(node);
let n2i = scenery.add_node(node);
let mut node= OpticNode::new("TFP", Box::new(NodeDummy));
node.set_inverted(true);
let n1i=scenery.add_node(node);
let mut node = OpticNode::new("TFP", NodeDummy);
node.set_inverted(true);
let n1i = scenery.add_node(node);
scenery.connect_nodes(n1, n2).unwrap();
scenery.connect_nodes(n2, n3).unwrap();
......@@ -35,11 +35,11 @@ fn main() {
scenery.connect_nodes(n3i, n2i).unwrap();
scenery.connect_nodes(n2i, n1i).unwrap();
let mut group=NodeGroup::new();
let g_n1=group.add_node(OpticNode::new("Beamsplitter", Box::new(NodeDummy)));
let g_n2=group.add_node(OpticNode::new("Lens", Box::new(NodeDummy)));
group.connect_nodes(g_n1,g_n2).unwrap();
scenery.add_node(OpticNode::new("CamBox", Box::new(group)));
let mut group = NodeGroup::new();
let g_n1 = group.add_node(OpticNode::new("Beamsplitter", NodeDummy));
let g_n2 = group.add_node(OpticNode::new("Lens", NodeDummy));
group.connect_nodes(g_n1, g_n2).unwrap();
scenery.add_node(OpticNode::new("CamBox", group));
let path = "graph.dot";
let mut output = File::create(path).unwrap();
write!(output, "{}", scenery.to_dot()).unwrap();
......
......@@ -5,7 +5,6 @@ use crate::optic_ports::OpticPorts;
pub struct OpticNode {
name: String,
node: Box<dyn Optical>,
inverted: bool,
ports: OpticPorts
}
......@@ -21,12 +20,11 @@ impl OpticNode {
///
/// let node=OpticNode::new("My node", Box::new(NodeDummy));
/// ```
pub fn new(name: &str, node_type: Box<dyn Optical>) -> Self {
pub fn new<T: Optical+ 'static>(name: &str, node_type: T) -> Self {
let ports=node_type.ports();
Self {
name: name.into(),
node: node_type,
inverted: false,
node: Box::new(node_type),
ports
}
}
......@@ -41,7 +39,7 @@ impl OpticNode {
/// Returns a string representation of the [`OpticNode`] in `graphviz` format. This function is normally called by the top-level `to_dot`function within
/// `OpticScenery`.
pub fn to_dot(&self, node_index: &str) -> String {
self.node.to_dot(node_index, &self.name, self.inverted)
self.node.to_dot(node_index, &self.name, self.inverted())
}
/// Returns the concrete node type as string representation.
pub fn node_type(&self) -> &str {
......@@ -51,11 +49,11 @@ impl OpticNode {
///
/// This means that the node is used in "reverse" direction. All output port become input parts and vice versa.
pub fn set_inverted(&mut self, inverted: bool) {
self.inverted = inverted;
self.ports.set_inverted(inverted)
}
/// Returns if the [`OpticNode`] is used in reversed direction.
pub fn inverted(&self) -> bool {
self.inverted
self.ports.inverted()
}
/// Returns a reference to the [`OpticPorts`] of this [`OpticNode`].
pub fn ports(&self) -> &OpticPorts {
......@@ -91,47 +89,47 @@ mod test {
use crate::nodes::NodeDummy;
#[test]
fn new() {
let node = OpticNode::new("Test", Box::new(NodeDummy));
let node = OpticNode::new("Test", NodeDummy);
assert_eq!(node.name, "Test");
assert_eq!(node.inverted, false);
assert_eq!(node.inverted(), false);
}
#[test]
fn set_name() {
let mut node = OpticNode::new("Test", Box::new(NodeDummy));
let mut node = OpticNode::new("Test", NodeDummy);
node.set_name("Test2".into());
assert_eq!(node.name, "Test2")
}
#[test]
fn name() {
let node = OpticNode::new("Test", Box::new(NodeDummy));
let node = OpticNode::new("Test", NodeDummy);
assert_eq!(node.name(), "Test")
}
#[test]
fn set_inverted() {
let mut node = OpticNode::new("Test", Box::new(NodeDummy));
let mut node = OpticNode::new("Test", NodeDummy);
node.set_inverted(true);
assert_eq!(node.inverted, true)
assert_eq!(node.inverted(), true)
}
#[test]
fn inverted() {
let mut node = OpticNode::new("Test", Box::new(NodeDummy));
let mut node = OpticNode::new("Test", NodeDummy);
node.set_inverted(true);
assert_eq!(node.inverted(), true)
}
#[test]
fn to_dot() {
let node = OpticNode::new("Test", Box::new(NodeDummy));
let node = OpticNode::new("Test", NodeDummy);
assert_eq!(node.to_dot("i0"), " i0 [label=\"Test\"]\n".to_owned())
}
#[test]
fn to_dot_inverted() {
let mut node = OpticNode::new("Test", Box::new(NodeDummy));
let mut node = OpticNode::new("Test", NodeDummy);
node.set_inverted(true);
assert_eq!(node.to_dot("i0"), " i0 [label=\"Test(inv)\"]\n".to_owned())
}
#[test]
fn node_type() {
let node = OpticNode::new("Test", Box::new(NodeDummy));
let node = OpticNode::new("Test", NodeDummy);
assert_eq!(node.node_type(), "dummy");
}
}
......@@ -5,6 +5,7 @@ use std::{collections::HashSet, mem::swap};
pub struct OpticPorts {
inputs: HashSet<String>,
outputs: HashSet<String>,
inverted: bool,
}
impl OpticPorts {
......@@ -12,10 +13,18 @@ impl OpticPorts {
Self::default()
}
pub fn inputs(&self) -> Vec<String> {
self.inputs.clone().into_iter().collect::<Vec<String>>()
if self.inverted {
self.outputs.clone().into_iter().collect::<Vec<String>>()
} else {
self.inputs.clone().into_iter().collect::<Vec<String>>()
}
}
pub fn outputs(&self) -> Vec<String> {
self.outputs.clone().into_iter().collect::<Vec<String>>()
if self.inverted {
self.inputs.clone().into_iter().collect::<Vec<String>>()
} else {
self.outputs.clone().into_iter().collect::<Vec<String>>()
}
}
pub fn add_input(&mut self, name: &str) -> Result<(), OpossumError> {
if self.inputs.insert(name.into()) {
......@@ -37,8 +46,13 @@ impl OpticPorts {
)))
}
}
pub fn invert(&mut self) {
swap(&mut self.inputs, &mut self.outputs);
pub fn set_inverted(&mut self, inverted: bool) {
self.inverted = inverted;
}
pub fn inverted(&self) -> bool {
self.inverted
}
}
......@@ -50,6 +64,7 @@ mod test {
let ports = OpticPorts::new();
assert_eq!(ports.inputs.len(), 0);
assert_eq!(ports.outputs.len(), 0);
assert_eq!(ports.inverted, false);
}
#[test]
fn add_input_ok() {
......@@ -82,17 +97,57 @@ mod test {
let mut ports = OpticPorts::new();
ports.add_input("Test1").unwrap();
ports.add_input("Test2").unwrap();
ports.add_output("Test3").unwrap();
ports.add_output("Test4").unwrap();
let mut v = ports.inputs();
v.sort();
assert_eq!(v, vec!["Test1".to_string(), "Test2".to_string()]);
}
#[test]
fn inputs_inverted() {
let mut ports = OpticPorts::new();
ports.set_inverted(true);
ports.add_input("Test1").unwrap();
ports.add_input("Test2").unwrap();
ports.add_output("Test3").unwrap();
ports.add_output("Test4").unwrap();
let mut v = ports.inputs();
v.sort();
assert_eq!(v, vec!["Test3".to_string(), "Test4".to_string()]);
}
#[test]
fn outputs() {
let mut ports = OpticPorts::new();
ports.add_output("Test1").unwrap();
ports.add_output("Test2").unwrap();
ports.add_input("Test1").unwrap();
ports.add_input("Test2").unwrap();
ports.add_output("Test3").unwrap();
ports.add_output("Test4").unwrap();
let mut v = ports.outputs();
v.sort();
assert_eq!(v, vec!["Test3".to_string(), "Test4".to_string()]);
}
#[test]
fn outputs_inverted() {
let mut ports = OpticPorts::new();
ports.set_inverted(true);
ports.add_input("Test1").unwrap();
ports.add_input("Test2").unwrap();
ports.add_output("Test3").unwrap();
ports.add_output("Test4").unwrap();
let mut v = ports.outputs();
v.sort();
assert_eq!(v, vec!["Test1".to_string(), "Test2".to_string()]);
}
#[test]
fn set_inverted() {
let mut ports = OpticPorts::new();
ports.set_inverted(true);
assert_eq!(ports.inverted, true);
}
#[test]
fn inverted() {
let mut ports = OpticPorts::new();
ports.set_inverted(true);
assert_eq!(ports.inverted(), true);
}
}
use crate::error::OpossumError;
use crate::optic_node::OpticNode;
use crate::optic_node::{OpticNode, Optical};
use petgraph::algo::*;
use petgraph::data::Build;
use petgraph::prelude::{DiGraph, EdgeIndex, NodeIndex};
type Result<T> = std::result::Result<T, OpossumError>;
......@@ -20,11 +21,19 @@ impl OpticScenery {
}
/// Add a given [`OpticNode`] to the graph of this [`OpticScenery`].
///
/// This command just adds an [`OpticNode`] but does not connect it to existing nodes in the graph. The given node is
/// consumed (owned) by the [`OpticScenery`].
/// This command just adds an [`OpticNode`] to the graph. It does not connect
/// it to existing nodes in the graph. The given optical element is consumed (owned) by the [`OpticScenery`].
pub fn add_node(&mut self, node: OpticNode) -> NodeIndex {
self.g.add_node(node)
}
/// Add a given optical element to the graph of this [`OpticScenery`].
///
/// This command just adds an optical element (a struct implementing the [`Optical`] trait such as `OpticDummy` ) to the graph. It does not connect
/// it to existing nodes in the graph. The given optical element is consumed (owned) by the [`OpticScenery`]. Internally the corresponding [`OpticNode`] is
/// automatically generated. It serves as a short-cut to the `add_node` function.
pub fn add_element<T: Optical + 'static>(&mut self, name: &str, t: T) -> NodeIndex {
self.g.add_node(OpticNode::new(name, t))
}
/// Get reference of [`OpticNode`].
///
/// Get the reference of an previously added [`OpticNode`] denoted by a given `NodeIndex`. This function can be used as input while
......@@ -45,15 +54,21 @@ impl OpticScenery {
target_node: NodeIndex,
) -> Result<EdgeIndex> {
if self.g.node_weight(src_node).is_none() {
return Err(OpossumError::OpticScenery("source node with gievn index does not exist".into()));
return Err(OpossumError::OpticScenery(
"source node with gievn index does not exist".into(),
));
}
if self.g.node_weight(target_node).is_none() {
return Err(OpossumError::OpticScenery("target node with given index does not exist".into()));
return Err(OpossumError::OpticScenery(
"target node with given index does not exist".into(),
));
}
let edge_index = self.g.add_edge(src_node, target_node, ());
if is_cyclic_directed(&self.g) {
self.g.remove_edge(edge_index);
return Err(OpossumError::OpticScenery("connecting the given nodes would form a loop".into()));
return Err(OpossumError::OpticScenery(
"connecting the given nodes would form a loop".into(),
));
}
Ok(edge_index)
}
......@@ -107,30 +122,36 @@ mod test {
#[test]
fn add_node() {
let mut scenery = OpticScenery::new();
scenery.add_node(OpticNode::new("Test", Box::new(NodeDummy)));
scenery.add_node(OpticNode::new("Test", NodeDummy));
assert_eq!(scenery.g.node_count(), 1);
}
#[test]
fn add_element() {
let mut scenery = OpticScenery::new();
scenery.add_element("Test", NodeDummy);
assert_eq!(scenery.g.node_count(), 1);
}
#[test]
fn connect_nodes_ok() {
let mut scenery = OpticScenery::new();
let n1 = scenery.add_node(OpticNode::new("Test", Box::new(NodeDummy)));
let n2 = scenery.add_node(OpticNode::new("Test", Box::new(NodeDummy)));
let n1 = scenery.add_element("Test", NodeDummy);
let n2 = scenery.add_element("Test", NodeDummy);
assert!(scenery.connect_nodes(n1, n2).is_ok());
assert_eq!(scenery.g.edge_count(), 1);
}
#[test]
fn connect_nodes_failure() {
let mut scenery = OpticScenery::new();
let n1 = scenery.add_node(OpticNode::new("Test", Box::new(NodeDummy)));
let n2 = scenery.add_node(OpticNode::new("Test", Box::new(NodeDummy)));
let n1 = scenery.add_element("Test", NodeDummy);
let n2 = scenery.add_element("Test", NodeDummy);
assert!(scenery.connect_nodes(n1, NodeIndex::new(5)).is_err());
assert!(scenery.connect_nodes(NodeIndex::new(5), n2).is_err());
}
#[test]
fn connect_nodes_loop_error() {
let mut scenery = OpticScenery::new();
let n1 = scenery.add_node(OpticNode::new("Test", Box::new(NodeDummy)));
let n2 = scenery.add_node(OpticNode::new("Test", Box::new(NodeDummy)));
let n1 = scenery.add_element("Test", NodeDummy);
let n2 = scenery.add_element("Test", NodeDummy);
assert!(scenery.connect_nodes(n1, n2).is_ok());
assert!(scenery.connect_nodes(n2, n1).is_err());
assert_eq!(scenery.g.edge_count(), 1);
......@@ -145,7 +166,7 @@ mod test {
fn to_dot_with_node() {
let mut scenery = OpticScenery::new();
scenery.set_description("SceneryTest".into());
scenery.add_node(OpticNode::new("Test", Box::new(NodeDummy)));
scenery.add_element("Test", NodeDummy);
assert_eq!(
scenery.to_dot(),
"digraph {\n label=\"SceneryTest\"\n fontname=\"Helvetica,Arial,sans-serif\"\n node [fontname=\"Helvetica,Arial,sans-serif\"]\n edge [fontname=\"Helvetica,Arial,sans-serif\"]\n i0 [label=\"Test\"]\n}"
......@@ -155,8 +176,8 @@ mod test {
fn to_dot_with_edge() {
let mut scenery = OpticScenery::new();
scenery.set_description("SceneryTest".into());
let n1 = scenery.add_node(OpticNode::new("Test1", Box::new(NodeDummy)));
let n2 = scenery.add_node(OpticNode::new("Test2", Box::new(NodeDummy)));
let n1 = scenery.add_element("Test1", NodeDummy);
let n2 = scenery.add_element("Test2", NodeDummy);
if let Ok(_) = scenery.connect_nodes(n1, n2) {
assert_eq!(
scenery.to_dot(),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment