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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use scad_element::*;

use std::vec::*;

/**
    An scad object which is a single scad element and can have zero or more child objects

    #How it works
    An scad object is a single `ScadElement` optionally followed by any number of child
    objects. This represents the following scad code:

    ```SCAD
    translate([1,2,3]) //parent
    {
        cube([3,5,1]); //Child
        //...
    }
    ```

    Without using the `scad!` macro, you would create an scad object by doing the 
    following.

    ```
    # use scad::*;
    //Create the parent
    let mut obj = ScadObject::new(ScadElement::Union);

    //add some children
    obj.add_child(ScadObject::new(ScadElement::Cube(vec3(1., 1., 1.))));
    //...
    ```

    This would be quite tedious to type each time you want to create a new object
    which is why the `scad!` macro exists. This does mean that if you want to add
    more children to an scad object created by the macro, you can simply use the 
    `add_child` function on the result of the macro. 
*/
#[derive(Clone)]
pub struct ScadObject 
{
    element: ScadElement,

    children: Vec<ScadObject>,

    //Decides wether or not the object should be drawn alone (by adding ! before)
    important: bool,
}

impl ScadObject 
{
    pub fn new(element: ScadElement) -> ScadObject 
    {
        ScadObject {
            element: element,

            children: Vec::new(),

            important: false,
        }
    }

    pub fn add_child(&mut self, statement: ScadObject) 
    {
        self.children.push(statement);
    }

    /**
      Returns the scad code for the object. 

      If there are no children, only the code for the ScadElement of the 
      object followed by a `;` is returned. If children exist, the code for 
      the element is returned first, followed by the code for each child surrounded
      by `{}` and indented 1 tab character.
    */
    pub fn get_code(&self) -> String 
    {
        let mut result: String;

        //Get the code for the current element
        result = self.element.clone().get_code();

        if self.important
        {
            result = String::from("!") + &result;
        }

        //Adding the code for all children, or ; if none exist
        result = result + &(match self.children.len()
        {
            0 => String::from(";"),
            _ => {
                    let mut child_code = String::from("\n{\n");
                    for stmt in &self.children 
                    {
                        //Add the children indented one line
                        child_code = child_code + "\t" + &(stmt.get_code().replace("\n", "\n\t"));
                        child_code = child_code + "\n";
                    }

                    //Add the final bracket and 'return' the result
                    child_code + "}"
                }
        });

        return result;
    }

    /**
      Marks the object as important. This will prepend the object code
      with an ! which tells scad to only render that object and its children.
    */
    pub fn is_important(&mut self)
    {
        self.important = true;
    }

    /**
      Takes ownership over the object, marks it as important and returns it.
      Usefull if you want to mark something as important without having to
      change the binding to mut
    */
    pub fn important(mut self) -> ScadObject
    {
        self.important = true;
        self
    }
}

#[cfg(test)]
mod statement_tests
{
    extern crate nalgebra as na;
    use scad_object::*;
    use scad_element::*;

    #[test]
    fn simple_stmt_test()
    {
        let mut test_stmt = ScadObject::new(ScadElement::Translate(na::Vector3::new(0.0, 0.0, 0.0)));

        assert_eq!(test_stmt.get_code(), "translate([0,0,0]);");

        test_stmt.add_child(ScadObject::new(ScadElement::Cube(na::Vector3::new(1.0, 1.0, 1.0))));
        assert_eq!(test_stmt.get_code(), "translate([0,0,0])\n{\n\tcube([1,1,1]);\n}");

        test_stmt.is_important();
        assert_eq!(test_stmt.get_code(), "!translate([0,0,0])\n{\n\tcube([1,1,1]);\n}");

        let test_2 = ScadObject::new(ScadElement::Union).important();
        assert_eq!(test_2.get_code(), "!union();");
    }
}