scad_tree/
scad.rs

1// MIT License
2//
3// Copyright (c) 2023 Michael H. Phillips
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22//
23
24use {crate::prelude::*, std::io::Write};
25
26/// The supported OpenSCAD operations.
27#[derive(Clone, PartialEq)]
28pub enum ScadOp {
29    Union,
30    Difference,
31    Intersection,
32    Circle {
33        radius: f64,
34        fa: Option<f64>,
35        fs: Option<f64>,
36        fn_: Option<u64>,
37    },
38    Square {
39        size: Pt2,
40        center: bool, // default false
41    },
42    Polygon {
43        points: Pt2s,
44        paths: Option<Paths>, // default None undef
45        convexity: u64,       // default 1
46    },
47    Text {
48        text: String,
49        size: f64,                // default 10
50        font: String,             // default "Liberation Sans"
51        halign: TextHalign,       // default left
52        valign: TextValign,       // default baseline
53        spacing: f64,             // default 1
54        direction: TextDirection, // default ltr
55        language: String,         // default "en"
56        script: String,           // default "latin"
57        fn_: Option<u64>,         // None
58    },
59    Import {
60        file: String,
61        convexity: u64,
62    },
63    Projection {
64        cut: bool,
65    },
66    Sphere {
67        radius: f64,
68        fa: Option<f64>,
69        fs: Option<f64>,
70        fn_: Option<u64>,
71    },
72    Cube {
73        size: Pt3,
74        center: bool,
75    },
76    Cylinder {
77        height: f64,
78        radius1: f64,
79        radius2: f64,
80        center: bool,
81        fa: Option<f64>,
82        fs: Option<f64>,
83        fn_: Option<u64>,
84    },
85    Polyhedron {
86        points: Pt3s,
87        faces: Faces,
88        convexity: u64,
89    },
90    LinearExtrude {
91        height: f64,
92        center: bool,
93        convexity: u64,
94        twist: f64,
95        scale: Pt2,
96        slices: Option<u64>,
97        fn_: Option<u64>,
98    },
99    RotateExtrude {
100        angle: f64,
101        convexity: u64,
102        fa: Option<f64>,
103        fs: Option<f64>,
104        fn_: Option<u64>,
105    },
106    Surface {
107        file: String,
108        center: bool,
109        invert: bool,
110        convexity: u64,
111    },
112    Translate {
113        v: Pt3,
114    },
115    Rotate {
116        a: Option<f64>,
117        a_is_scalar: bool,
118        v: Pt3,
119    },
120    Scale {
121        v: Pt3,
122    },
123    Resize {
124        newsize: Pt3,
125        auto: bool,
126        auto_is_vec: bool,
127        autovec: (bool, bool, bool),
128        convexity: u64,
129    },
130    Mirror {
131        v: Pt3,
132    },
133    Color {
134        rgba: Option<Pt4>,
135        color: Option<ScadColor>,
136        hex: Option<String>,
137        alpha: Option<f64>,
138    },
139    Offset {
140        r: Option<f64>,
141        delta: Option<f64>,
142        chamfer: bool,
143    },
144    Hull,
145    Minkowski {
146        convexity: u64,
147    },
148}
149
150/// A tree of OpenSCAD operations.
151///
152/// Should not need to construct manually in end user code. We
153/// have macros and functions to do it for us.
154#[derive(Clone, PartialEq)]
155pub struct Scad {
156    pub op: ScadOp,
157    pub children: Vec<Scad>,
158}
159
160impl Scad {
161    /// Creates a curved chamfer shape.
162    ///
163    /// size: The size of the angled part of the chamfer profile.
164    ///
165    /// oversize: How much non-angled part there is on the chamfer.
166    ///
167    /// radius: The radius of the arc that the chamfer takes.
168    ///
169    /// degrees: The degrees of the arc that the chamfer is extruded through.
170    ///
171    /// segments: The number of segments in a circle.
172    ///
173    /// return: The mesh.
174    pub fn external_circle_chamfer(
175        size: f64,
176        oversize: f64,
177        radius: f64,
178        degrees: f64,
179        segments: u64,
180    ) -> Self {
181        rotate_extrude!(angle=degrees, convexity=5, fn=segments,
182            translate!([radius + size / 2.0 + oversize / 2.0, -oversize, 0.0],
183                rotate!(90.0,
184                    polygon!(dim2::chamfer(size, oversize));
185                );
186            );
187        )
188    }
189
190    /// Creates two external circle chamfers for chamfering a cylinder.
191    ///
192    /// size: The size of the angled part of the chamfer profile.
193    ///
194    /// oversize: How much non-angled part there is on the chamfer.
195    ///
196    /// radius: The radius of the cylinder to be chamfered.
197    ///
198    /// height: The height of the cylinder to be chamfered.
199    ///
200    /// segments: The number of segments in a circle.
201    ///
202    /// return: The mesh.
203    pub fn external_cylinder_chamfer(
204        size: f64,
205        oversize: f64,
206        radius: f64,
207        height: f64,
208        segments: u64,
209        center: bool,
210    ) -> Self {
211        let mut result = union!(
212            Self::external_circle_chamfer(size, oversize, radius, 360.0, segments);
213            translate!([0.0, 0.0, height],
214                rotate!([180.0, 0.0, 0.0],
215                    Self::external_circle_chamfer(size, oversize, radius, 360.0, segments);
216                );
217            );
218        );
219        if center {
220            result = translate!([0.0, 0.0, -height/2.0], result;);
221        }
222        result
223    }
224
225    /// Create a circular array around the Z axis
226    pub fn polar_array(scad: &Scad, count: u64, degrees: f64) -> Scad {
227        assert!(degrees <= 360.0);
228        let steps = if degrees == 360.0 { count } else { count - 1 };
229        let mut result = scad.clone();
230        for i in 0..count {
231            let a = i as f64 * -degrees / steps as f64;
232            result = result + rotate!([0.0, 0.0, a], scad.clone(););
233        }
234        result
235    }
236
237    pub fn save(&self, path: &str) {
238        let s = format!("{}", self);
239        let mut file = std::fs::File::create(path).unwrap();
240        file.write_all(s.as_bytes()).unwrap();
241        file.flush().unwrap();
242    }
243}
244
245impl std::ops::Sub for Scad {
246    type Output = Self;
247
248    fn sub(self, rhs: Self) -> Self::Output {
249        difference!(self; rhs;)
250    }
251}
252
253impl std::ops::Add for Scad {
254    type Output = Self;
255
256    fn add(self, rhs: Self) -> Self::Output {
257        union!(self; rhs;)
258    }
259}
260
261/// Since we are outputting text we leverage the Display trait to format output.
262impl std::fmt::Display for Scad {
263    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264        match &self.op {
265            ScadOp::Union => {
266                writeln!(f, "union() {{")?;
267            }
268            ScadOp::Difference => {
269                writeln!(f, "difference() {{")?;
270            }
271            ScadOp::Intersection => {
272                writeln!(f, "intersection() {{")?;
273            }
274            ScadOp::Circle {
275                radius,
276                fa,
277                fs,
278                fn_,
279            } => {
280                write!(f, "circle(r={}", radius)?;
281                if let Some(fa) = fa {
282                    write!(f, ", $fa={}", fa)?;
283                }
284                if let Some(fs) = fs {
285                    write!(f, ", $fs={}", fs)?;
286                }
287                if let Some(fn_) = fn_ {
288                    write!(f, ", $fn={}", fn_)?;
289                }
290                write!(f, ");")?;
291            }
292            ScadOp::Square { size, center } => {
293                write!(
294                    f,
295                    "square(size=[{}, {}], center={});",
296                    size.x, size.y, center
297                )?;
298            }
299            ScadOp::Polygon {
300                points,
301                paths,
302                convexity,
303            } => {
304                if let Some(paths) = paths {
305                    write!(
306                        f,
307                        "polygon(points={}, paths={} convexity={});",
308                        points, paths, convexity
309                    )?;
310                } else {
311                    write!(
312                        f,
313                        "polygon(points={}, paths=undef, convexity={});",
314                        points, convexity
315                    )?;
316                }
317            }
318            ScadOp::Text {
319                text,
320                size,
321                font,
322                halign,
323                valign,
324                spacing,
325                direction,
326                language,
327                script,
328                fn_,
329            } => {
330                write!(f, "text(text={:?}, ", text)?;
331                write!(f, "size={}, ", size)?;
332                write!(f, "font={:?}, ", font)?;
333                write!(f, "halign=\"{:?}\", ", halign)?;
334                write!(f, "valign=\"{:?}\", ", valign)?;
335                write!(f, "spacing={}, ", spacing)?;
336                write!(f, "direction=\"{:?}\", ", direction)?;
337                write!(f, "language={:?}, ", language)?;
338                write!(f, "script={:?}", script)?;
339                if let Some(fn_) = fn_ {
340                    write!(f, ", $fn={}", fn_)?;
341                }
342                write!(f, ");")?;
343            }
344            ScadOp::Import { file, convexity } => {
345                write!(f, "import({:?}, {});", file, convexity)?;
346            }
347            ScadOp::Projection { cut } => {
348                writeln!(f, "projection(cut={}) {{", cut)?;
349            }
350            ScadOp::Sphere {
351                radius,
352                fa,
353                fs,
354                fn_,
355            } => {
356                write!(f, "sphere(r={}", radius)?;
357                if let Some(fa) = fa {
358                    write!(f, ", $fa={}", fa)?;
359                }
360                if let Some(fs) = fs {
361                    write!(f, ", $fs={}", fs)?;
362                }
363                if let Some(fn_) = fn_ {
364                    write!(f, ", $fn={}", fn_)?;
365                }
366                write!(f, ");")?;
367            }
368            ScadOp::Cube { size, center } => {
369                write!(f, "cube(size={}, center={});", size, center)?;
370            }
371            ScadOp::Cylinder {
372                height,
373                radius1,
374                radius2,
375                center,
376                fa,
377                fs,
378                fn_,
379            } => {
380                write!(
381                    f,
382                    "cylinder(h={}, r1={}, r2={}, center={}",
383                    height, radius1, radius2, center
384                )?;
385                if let Some(fa) = fa {
386                    write!(f, ", $fa={}", fa)?;
387                }
388                if let Some(fs) = fs {
389                    write!(f, ", $fs={}", fs)?;
390                }
391                if let Some(fn_) = fn_ {
392                    write!(f, ", $fn={}", fn_)?;
393                }
394                write!(f, ");")?;
395            }
396            ScadOp::Polyhedron {
397                points,
398                faces,
399                convexity,
400            } => {
401                write!(
402                    f,
403                    "polyhedron(points={}, faces={}, convexity={});",
404                    points, faces, convexity
405                )?;
406            }
407            ScadOp::LinearExtrude {
408                height,
409                center,
410                convexity,
411                twist,
412                scale,
413                slices,
414                fn_,
415            } => {
416                write!(
417                    f,
418                    "linear_extrude(height={}, center={}, convexity={}, twist={}, scale={}",
419                    height, center, convexity, twist, scale
420                )?;
421                if let Some(slices) = slices {
422                    write!(f, ", slices={}", slices)?;
423                }
424                if let Some(fn_) = fn_ {
425                    write!(f, ", $fn={}", fn_)?;
426                }
427                writeln!(f, ") {{")?;
428            }
429            ScadOp::RotateExtrude {
430                angle,
431                convexity,
432                fa,
433                fs,
434                fn_,
435            } => {
436                write!(f, "rotate_extrude(angle={}, convexity={}", angle, convexity)?;
437                if let Some(fa) = fa {
438                    write!(f, ", $fa={}", fa)?;
439                }
440                if let Some(fs) = fs {
441                    write!(f, ", $fs={}", fs)?;
442                }
443                if let Some(fn_) = fn_ {
444                    write!(f, ", $fn={}", fn_)?;
445                }
446                writeln!(f, ") {{")?;
447            }
448            ScadOp::Surface {
449                file,
450                center,
451                invert,
452                convexity,
453            } => {
454                write!(
455                    f,
456                    "surface(file={:?}, center={}, invert={}, convexity={});",
457                    file, center, invert, convexity
458                )?;
459            }
460            ScadOp::Translate { v } => {
461                writeln!(f, "translate(v={}) {{", v)?;
462            }
463            ScadOp::Rotate { a, a_is_scalar, v } => {
464                if let Some(a) = a {
465                    if *a_is_scalar {
466                        writeln!(f, "rotate(a={}) {{", a)?;
467                    } else {
468                        writeln!(f, "rotate(a={}, v={}) {{", a, v)?;
469                    }
470                } else {
471                    writeln!(f, "rotate(a={}) {{", v)?;
472                }
473            }
474            ScadOp::Scale { v } => {
475                writeln!(f, "scale(v={}) {{", v)?;
476            }
477            ScadOp::Resize {
478                newsize,
479                auto,
480                auto_is_vec,
481                autovec,
482                convexity,
483            } => {
484                if *auto_is_vec {
485                    writeln!(
486                        f,
487                        "resize(newsize={}, auto={}, convexity={}) {{",
488                        newsize, auto, convexity
489                    )?;
490                } else {
491                    writeln!(
492                        f,
493                        "resize(newsize={}, auto=[{}, {}, {}], convexity={}) {{",
494                        newsize, autovec.0, autovec.1, autovec.2, convexity
495                    )?;
496                }
497            }
498            ScadOp::Mirror { v } => {
499                writeln!(f, "mirror(v={}) {{", v)?;
500            }
501            ScadOp::Color {
502                rgba,
503                color,
504                hex,
505                alpha,
506            } => {
507                if let Some(rgba) = rgba {
508                    writeln!(f, "color(c={}) {{", rgba)?;
509                } else if let Some(color) = color {
510                    write!(f, "color(\"{:?}\"", color)?;
511                    if let Some(alpha) = alpha {
512                        write!(f, ", alpha={}", alpha)?;
513                    }
514                    writeln!(f, ") {{")?;
515                } else if let Some(hex) = hex {
516                    writeln!(f, "color({:?}) {{", hex)?;
517                }
518            }
519            ScadOp::Offset { r, delta, chamfer } => {
520                if let Some(r) = r {
521                    writeln!(f, "offset(r={}) {{", r)?;
522                } else if let Some(delta) = delta {
523                    writeln!(f, "offset(delta={}, chamfer={}) {{", delta, chamfer)?;
524                }
525            }
526            ScadOp::Hull => {
527                writeln!(f, "hull() {{")?;
528            }
529            ScadOp::Minkowski { convexity } => {
530                writeln!(f, "minkowski(convexity={}) {{", convexity)?;
531            }
532        } // end match
533        for i in 0..self.children.len() {
534            write!(f, "{}", self.children[i])?;
535        }
536        if !self.children.is_empty() {
537            write!(f, "}}")?;
538        }
539        writeln!(f)
540    }
541}
542
543/// Enum of all the named OpenSCAD colors
544#[derive(Clone, Copy, Debug, PartialEq)]
545pub enum ScadColor {
546    Lavender,
547    Thistle,
548    Plum,
549    Violet,
550    Orchid,
551    Fuchsia,
552    Magenta,
553    MediumOrchid,
554    MediumPurple,
555    BlueViolet,
556    DarkViolet,
557    DarkOrchid,
558    DarkMagenta,
559    Purple,
560    Indigo,
561    DarkSlateBlue,
562    SlateBlue,
563    MediumSlateBlue,
564    Pink,
565    LightPink,
566    HotPink,
567    DeepPink,
568    MediumVioletRed,
569    PaleVioletRed,
570    Aqua,
571    Cyan,
572    LightCyan,
573    PaleTurquoise,
574    Aquamarine,
575    Turquoise,
576    MediumTurquoise,
577    DarkTurquoise,
578    CadetBlue,
579    SteelBlue,
580    LightSteelBlue,
581    PowderBlue,
582    LightBlue,
583    SkyBlue,
584    LightSkyBlue,
585    DeepSkyBlue,
586    DodgerBlue,
587    CornflowerBlue,
588    RoyalBlue,
589    Blue,
590    MediumBlue,
591    DarkBlue,
592    Navy,
593    MidnightBlue,
594    IndianRed,
595    LightCoral,
596    Salmon,
597    DarkSalmon,
598    LightSalmon,
599    Red,
600    Crimson,
601    FireBrick,
602    DarkRed,
603    GreenYellow,
604    Chartreuse,
605    LawnGreen,
606    Lime,
607    LimeGreen,
608    PaleGreen,
609    LightGreen,
610    MediumSpringGreen,
611    SpringGreen,
612    MediumSeaGreen,
613    SeaGreen,
614    ForestGreen,
615    Green,
616    DarkGreen,
617    YellowGreen,
618    OliveDrab,
619    Olive,
620    DarkOliveGreen,
621    MediumAquamarine,
622    DarkSeaGreen,
623    LightSeaGreen,
624    DarkCyan,
625    Teal,
626    Coral,
627    Tomato,
628    OrangeRed,
629    DarkOrange,
630    Orange,
631    Gold,
632    Yellow,
633    LightYellow,
634    LemonChiffon,
635    LightGoldenrodYellow,
636    PapayaWhip,
637    Moccasin,
638    PeachPuff,
639    PaleGoldenrod,
640    Khaki,
641    DarkKhaki,
642    Browns,
643    Cornsilk,
644    BlanchedAlmond,
645    Bisque,
646    NavajoWhite,
647    Wheat,
648    BurlyWood,
649    Tan,
650    RosyBrown,
651    SandyBrown,
652    Goldenrod,
653    DarkGoldenrod,
654    Peru,
655    Chocolate,
656    SaddleBrown,
657    Sienna,
658    Brown,
659    Maroon,
660    White,
661    Snow,
662    Honeydew,
663    MintCream,
664    Azure,
665    AliceBlue,
666    GhostWhite,
667    WhiteSmoke,
668    Seashell,
669    Beige,
670    OldLace,
671    FloralWhite,
672    Ivory,
673    AntiqueWhite,
674    Linen,
675    LavenderBlush,
676    MistyRose,
677    Gainsboro,
678    LightGrey,
679    Silver,
680    DarkGray,
681    Gray,
682    DimGray,
683    LightSlateGray,
684    SlateGray,
685    DarkSlateGray,
686    Black,
687}
688
689/// The ways for horizontal alignment of text.
690#[allow(non_camel_case_types)]
691#[derive(Clone, Copy, PartialEq, Debug)]
692pub enum TextHalign {
693    left, // default
694    center,
695    right,
696}
697
698/// The ways for vertical alignment of text.
699#[allow(non_camel_case_types)]
700#[derive(Clone, Copy, PartialEq, Debug)]
701pub enum TextValign {
702    top,
703    center,
704    baseline, // default
705    bottom,
706}
707
708/// The possible directions of text.
709#[allow(non_camel_case_types)]
710#[derive(Clone, Copy, PartialEq, Debug)]
711pub enum TextDirection {
712    ltr, // left to right default
713    rtl, // right to left
714    ttb, // top to bottom
715    btt, // bottom to top
716}
717
718/// Text macro parameters
719///
720/// There are numerous parameters that can be passed to the text macro. This struct
721/// can be passed instead for convenience.
722#[derive(Clone)]
723pub struct TextParams {
724    pub text: String,
725    pub size: f64,
726    pub font: String,
727    pub halign: TextHalign,
728    pub valign: TextValign,
729    pub spacing: f64,
730    pub direction: TextDirection,
731    pub language: String,
732    pub script: String,
733    pub fn_: Option<u64>,
734}
735
736impl Default for TextParams {
737    fn default() -> Self {
738        Self {
739            text: Default::default(),
740            size: 10.0,
741            font: "Liberation Sans".to_string(),
742            halign: TextHalign::left,
743            valign: TextValign::baseline,
744            spacing: 1.0,
745            direction: TextDirection::ltr,
746            language: "en".to_string(),
747            script: "latin".to_string(),
748            fn_: None,
749        }
750    }
751}
752
753/// Saves Scad objects to a file in a separate thread.
754///
755/// Allows setting global $fa, $fs, or $fn. $fn overrides $fa and
756/// $fs so cannot be specified with $fa or $fs.
757///
758/// #params
759///
760/// stack_size: The size of the stack in megabytes.
761///
762/// path: The path of the file to save.
763///
764/// fa: The minimum angle between segments or faces.
765///
766/// fs: The minimum length of a segment or face.
767///
768/// fn: The number of segments or faces in a circle.
769///
770/// children: A list of one or more Scad objects separated and terminated with a semicolon.
771///
772/// #patterns
773///
774/// scad_file!('stack_size: usize', 'path: &str', 'children: Scad';);
775///
776/// scad_file!('stack_size: usize', 'path: &str', fa='fa: f64', 'children: Scad';);
777///
778/// scad_file!('stack_size: usize', 'path: &str', fs='fs: f64', 'children: Scad';);
779///
780/// scad_file!('stack_size: usize', 'path: &str', fa='fa: f64', fs='fs: f64', 'children: Scad';);
781///
782/// scad_file!('stack_size: usize', 'path: &str', fn='fn: u64', 'children: Scad';);
783#[macro_export]
784macro_rules! scad_file {
785    ($stack_size:expr, $path:expr, fa=$fa:expr, fs=$fs:expr, $($child:expr);+;) => {
786        let t = fat_thread!($stack_size, {
787            let children = vec![$($child,)+];
788            let mut file = std::fs::File::create($path).unwrap();
789            file.write_all(format!("$fa={};\n", $fa).as_bytes()).unwrap();
790            file.write_all(format!("$fs={};\n", $fs).as_bytes()).unwrap();
791            for child in children {
792                let s = format!("{}", child);
793                file.write_all(s.as_bytes()).unwrap();
794            }
795            file.flush().unwrap();
796        });
797        t.join().unwrap();
798    };
799    ($stack_size:expr, $path:expr, fn=$fn:expr, $($child:expr);+;) => {
800        let t = fat_thread!($stack_size, {
801            let children = vec![$($child,)+];
802            let mut file = std::fs::File::create($path).unwrap();
803            file.write_all(format!("$fn={};\n", $fn).as_bytes()).unwrap();
804            for child in children {
805                let s = format!("{}", child);
806                file.write_all(s.as_bytes()).unwrap();
807            }
808            file.flush().unwrap();
809        });
810        t.join().unwrap();
811    };
812    ($stack_size:expr, $path:expr, fs=$fs:expr, $($child:expr);+;) => {
813        let t = fat_thread!($stack_size, {
814            let children = vec![$($child,)+];
815            let mut file = std::fs::File::create($path).unwrap();
816            file.write_all(format!("$fs={};\n", $fs).as_bytes()).unwrap();
817            for child in children {
818                let s = format!("{}", child);
819                file.write_all(s.as_bytes()).unwrap();
820            }
821            file.flush().unwrap();
822        });
823        t.join().unwrap();
824    };
825    ($stack_size:expr, $path:expr, fa=$fa:expr, $($child:expr);+;) => {
826        let t = fat_thread!($stack_size, {
827            let children = vec![$($child,)+];
828            let mut file = std::fs::File::create($path).unwrap();
829            file.write_all(format!("$fa={};\n", $fa).as_bytes()).unwrap();
830            for child in children {
831                let s = format!("{}", child);
832                file.write_all(s.as_bytes()).unwrap();
833            }
834            file.flush().unwrap();
835        });
836        t.join().unwrap();
837    };
838    ($stack_size:expr, $path:expr, $($child:expr);+;) => {
839        let t = fat_thread!($stack_size, {
840            let children = vec![$($child,)+];
841            let mut file = std::fs::File::create($path).unwrap();
842            for child in children {
843                let s = format!("{}", child);
844                file.write_all(s.as_bytes()).unwrap();
845            }
846            file.flush().unwrap();
847        });
848        t.join().unwrap();
849    };
850}
851
852/// Constructive Solid Geometry union operation.
853///
854/// Combines multiple shapes into one.
855///
856/// #params
857///
858/// Scad structs seperated by and ending with a seimicolon.
859#[macro_export]
860macro_rules! union {
861    ($($child:expr);+;) => {
862        Scad {
863            op: ScadOp::Union,
864            children: vec![$($child,)+],
865        }
866    };
867}
868
869/// Constructive Solid Geometry difference operation.
870///
871/// Subracts all subsequent shapes from the first shape.
872///
873/// #params
874///
875/// Scad structs seperated by and ending with a seimicolon.
876#[macro_export]
877macro_rules! difference {
878  ($($child:expr);+;) => {
879    Scad {
880      op: ScadOp::Difference,
881      children: vec![$($child,)+],
882    }
883  };
884}
885
886/// Constructive Solid Geometry intersection operation.
887///
888/// Yields the overlapping area of the given shapes.
889///
890/// #params
891///
892/// Scad structs seperated by and ending with a seimicolon.
893#[macro_export]
894macro_rules! intersection {
895    ($($child:expr);+;) => {
896        Scad {
897            op: ScadOp::Intersection,
898            children: vec![$($child,)+],
899        }
900    };
901}
902
903/// Creates a circle.
904///
905/// #params
906///
907/// diameter: The diameter of the circle.
908///
909/// radius: The radius of the circle.
910///
911/// fa: The minimum angle between segments.
912///
913/// fs: The minimum length of a segment.
914///
915/// fn: The number of segments in the circle.
916///
917/// expansion: Scad struct literal.
918///
919/// #patterns
920///
921/// circle!('radius: f64');
922///
923/// circle!('radius: f64', fn='fn: u64');
924///
925/// circle!('radius: f64', fa='fa: f64');
926///
927/// circle!('radius: f64', fs='fs: f64');
928///
929/// circle!('radius: f64', fa='fa: f64', fs='fs: f64');
930///
931/// circle!(d='diameter: f64');
932///
933/// circle!(d='diameter: f64', fn='fn: u64');
934///
935/// circle!(d='diameter: f64', fa='fa: f64');
936///
937/// circle!(d='diameter: f64', fs='fs: f64');
938///
939/// circle!(d='diameter: f64', fa='fa: f64', fs='fs: f64');
940///
941/// circle!(r='radius: f64');
942///
943/// circle!(r='radius: f64', fn='fn: u64');
944///
945/// circle!(r='radius: f64', fa='fa: f64');
946///
947/// circle!(r='radius: f64', fs='fs: f64');
948///
949/// circle!(r='radius: f64', fa='fa: f64', fs='fs: f64');
950#[macro_export]
951macro_rules! circle {
952    (d=$dia:expr) => {
953        Scad {
954            op: ScadOp::Circle {
955                radius: $dia / 2.0,
956                fa: None,
957                fs: None,
958                fn_: None,
959            },
960            children: Vec::new(),
961        }
962    };
963    (d=$dia:expr, fn=$fn:expr) => {
964        Scad {
965            op: ScadOp::Circle {
966                radius: $dia / 2.0,
967                fa: None,
968                fs: None,
969                fn_: Some($fn),
970            },
971            children: Vec::new(),
972        }
973    };
974    (d=$dia:expr, fa=$fa:expr) => {
975        Scad {
976            op: ScadOp::Circle {
977                radius: $dia / 2.0,
978                fa: Some($fa),
979                fs: None,
980                fn_: None,
981            },
982            children: Vec::new(),
983        }
984    };
985    (d=$dia:expr, fs=$fs:expr) => {
986        Scad {
987            op: ScadOp::Circle {
988                radius: $dia / 2.0,
989                fa: None,
990                fs: Some($fs),
991                fn_: None,
992            },
993            children: Vec::new(),
994        }
995    };
996    (d=$dia:expr, fa=$fa:expr, fs=$fs:expr) => {
997        Scad {
998            op: ScadOp::Circle {
999                radius: $dia / 2.0,
1000                fa: Some($fa),
1001                fs: Some($fs),
1002                fn_: None,
1003            },
1004            children: Vec::new(),
1005        }
1006    };
1007    (r=$r:expr) => {
1008        Scad {
1009            op: ScadOp::Circle {
1010                radius: $r,
1011                fa: None,
1012                fs: None,
1013                fn_: None,
1014            },
1015            children: Vec::new(),
1016        }
1017    };
1018    (r=$r:expr, fn=$fn:expr) => {
1019        Scad {
1020            op: ScadOp::Circle {
1021                radius: $r,
1022                fa: None,
1023                fs: None,
1024                fn_: Some($fn),
1025            },
1026            children: Vec::new(),
1027        }
1028    };
1029    (r=$r:expr, fa=$fa:expr) => {
1030        Scad {
1031            op: ScadOp::Circle {
1032                radius: $r,
1033                fa: Some($fa),
1034                fs: None,
1035                fn_: None,
1036            },
1037            children: Vec::new(),
1038        }
1039    };
1040    (r=$r:expr, fs=$fs:expr) => {
1041        Scad {
1042            op: ScadOp::Circle {
1043                radius: $r,
1044                fa: None,
1045                fs: Some($fs),
1046                fn_: None,
1047            },
1048            children: Vec::new(),
1049        }
1050    };
1051    (r=$r:expr, fa=$fa:expr, fs=$fs:expr) => {
1052        Scad {
1053            op: ScadOp::Circle {
1054                radius: $r,
1055                fa: Some($fa),
1056                fs: Some($fs),
1057                fn_: None,
1058            },
1059            children: Vec::new(),
1060        }
1061    };
1062    ($r:expr, fa=$fa:expr) => {
1063        Scad {
1064            op: ScadOp::Circle {
1065                radius: $r,
1066                fa: Some($fa),
1067                fs: None,
1068                fn_: None,
1069            },
1070            children: Vec::new(),
1071        }
1072    };
1073    ($r:expr, fs=$fs:expr) => {
1074        Scad {
1075            op: ScadOp::Circle {
1076                radius: $r,
1077                fa: None,
1078                fs: Some($fs),
1079                fn_: None,
1080            },
1081            children: Vec::new(),
1082        }
1083    };
1084    ($r:expr, fa=$fa:expr, fs=$fs:expr) => {
1085        Scad {
1086            op: ScadOp::Circle {
1087                radius: $r,
1088                fa: Some($fa),
1089                fs: Some($fs),
1090                fn_: None,
1091            },
1092            children: Vec::new(),
1093        }
1094    };
1095    ($r:expr) => {
1096        Scad {
1097            op: ScadOp::Circle {
1098                radius: $r,
1099                fa: None,
1100                fs: None,
1101                fn_: None,
1102            },
1103            children: Vec::new(),
1104        }
1105    };
1106    ($r:expr, fn=$fn:expr) => {
1107        Scad {
1108            op: ScadOp::Circle {
1109                radius: $r,
1110                fa: None,
1111                fs: None,
1112                fn_: Some($fn),
1113            },
1114            children: Vec::new(),
1115        }
1116    };
1117}
1118
1119/// Creates a square or rectangle.
1120///
1121/// #params
1122///
1123/// x: The x dimensions.
1124///
1125/// y: The y dimensions.
1126///
1127/// size: The size of a side for a square.
1128///
1129/// center: Whether to center the square or leave it in the 1st quadrant.
1130///
1131/// expansion: Scad struct literal.
1132///
1133/// #patterns
1134///
1135/// square!(\['x: f64', 'y: f64'\]);
1136///
1137/// square!(\['x: f64', 'y: f64'\], 'center: bool');
1138///
1139/// square!('size: f64');
1140///
1141/// square!('size: f64, 'center: bool');
1142#[macro_export]
1143macro_rules! square {
1144    ([$x:expr, $y:expr]) => {
1145        Scad {
1146            op: ScadOp::Square {
1147                size: Pt2::new($x, $y),
1148                center: false,
1149            },
1150            children: Vec::new(),
1151        }
1152    };
1153    ([$x:expr, $y:expr], $center:expr) => {
1154        Scad {
1155            op: ScadOp::Square {
1156                size: Pt2::new($x, $y),
1157                center: $center,
1158            },
1159            children: Vec::new(),
1160        }
1161    };
1162    ($size:expr) => {
1163        Scad {
1164            op: ScadOp::Square {
1165                size: Pt2::new($size, $size),
1166                center: false,
1167            },
1168            children: Vec::new(),
1169        }
1170    };
1171    ($size:expr, $center:expr) => {
1172        Scad {
1173            op: ScadOp::Square {
1174                size: Pt2::new($size, $size),
1175                center: $center,
1176            },
1177            children: Vec::new(),
1178        }
1179    };
1180}
1181
1182/// Creates a polygon.
1183///
1184/// #params
1185///
1186/// points: The points that make up the polygon.
1187///
1188/// paths: The order of the points.
1189///
1190/// convexity: Number of inward curves, only for the preview.
1191///
1192/// expansion: The Scad struct literal.
1193///
1194/// #patterns
1195///
1196/// polygon!('points: Pt2s');
1197///
1198/// polygon!('points: Pt2s', 'paths: Paths');
1199///
1200/// polygon!('points: Pt2s', 'paths: Paths', 'convexity: u64');
1201///
1202/// polygon!('points: Pt2s', convexity='convexity: u64');
1203#[macro_export]
1204macro_rules! polygon {
1205    ($points:expr, convexity=$convexity:expr) => {
1206        Scad {
1207            op: ScadOp::Polygon {
1208                points: $points,
1209                paths: None,
1210                convexity: $convexity,
1211            },
1212            children: Vec::new(),
1213        }
1214    };
1215    ($points:expr, $paths:expr, $convexity:expr) => {
1216        Scad {
1217            op: ScadOp::Polygon {
1218                points: $points,
1219                paths: Some($paths),
1220                convexity: $convexity,
1221            },
1222            children: Vec::new(),
1223        }
1224    };
1225    ($points:expr, $paths:expr) => {
1226        Scad {
1227            op: ScadOp::Polygon {
1228                points: $points,
1229                paths: Some($paths),
1230                convexity: 1,
1231            },
1232            children: Vec::new(),
1233        }
1234    };
1235    ($points:expr) => {
1236        Scad {
1237            op: ScadOp::Polygon {
1238                points: $points,
1239                paths: None,
1240                convexity: 1,
1241            },
1242            children: Vec::new(),
1243        }
1244    };
1245}
1246
1247/// Creates text.
1248///
1249/// #params
1250///
1251/// text: The text to display.
1252///
1253/// size: The size of the text.
1254///
1255/// font: The font for the text.
1256///
1257/// halign: Horizontal alignment of text.
1258///
1259/// valign: Vertical alignment of text.
1260///
1261/// spacing: The space between characters.
1262///
1263/// language: The language for the text "en" default.
1264///
1265/// script: The script for the text "latin" default.
1266///
1267/// fn: The number of segments in a circle.
1268///
1269/// text_params: A TextParams struct with the above members.
1270///
1271/// expansion: Scad struct literal.
1272///
1273/// #patterns
1274///
1275/// text!('text: &str');
1276///
1277/// text!(text_params='text_params: TextParams');
1278///
1279/// text!('text: &str', 'size: f64');
1280///
1281/// text!('text: &str', 'size: f64', 'font: &str');
1282///
1283/// text!('text: &str', fn='fn: u64');
1284///
1285/// text!('text: &str', 'size: f64', fn='fn: u64');
1286///
1287/// text!('text: &str', 'size: f64', 'font: &str', fn='fn: u64');
1288///
1289/// text!('text: &str', 'size: f64', 'font: &str', 'halign: TextHalign', 'valign: TextValign', 'direction: TextDirection');
1290///
1291/// text!('text: &str', 'size: f64', 'font: &str', 'halign: TextHalign', 'valign: TextValign', 'direction: TextDirection', fn='fn: u64');
1292///
1293/// text!('text: &str', 'size: f64', 'font: &str', 'halign: TextHalign', 'valign: TextValign', 'spacing: f64', 'direction: TextDirection', 'language: &str', 'script: &str', 'fn: u64');
1294#[macro_export]
1295macro_rules! text {
1296    (text_params=$params:expr) => {
1297        Scad {
1298            op: ScadOp::Text {
1299                text: $params.text,
1300                size: $params.size,
1301                font: $params.font,
1302                halign: $params.halign,
1303                valign: $params.valign,
1304                spacing: $params.spacing,
1305                direction: $params.direction,
1306                language: $params.language,
1307                script: $params.script,
1308                fn_: $params.fn_,
1309            },
1310            children: Vec::new(),
1311        }
1312    };
1313    ($text:expr, $size:expr, $font:expr, $halign:expr, $valign:expr, $spacing:expr, $direction:expr, $language:expr, $script:expr, $fn:expr) => {
1314        Scad {
1315            op: ScadOp::Text {
1316                text: $text.to_string(),
1317                size: $size,
1318                font: $font.to_string(),
1319                halign: $halign,
1320                valign: $valign,
1321                spacing: $spacing,
1322                direction: $direction,
1323                language: $language.to_string(),
1324                script: $script.to_string(),
1325                fn_: Some($fn),
1326            },
1327            children: Vec::new(),
1328        }
1329    };
1330    ($text:expr, $size:expr, $font:expr, $halign:expr, $valign:expr, $direction:expr, fn=$fn:expr) => {
1331        Scad {
1332            op: ScadOp::Text {
1333                text: $text.to_string(),
1334                size: $size,
1335                font: $font.to_string(),
1336                halign: $halign,
1337                valign: $valign,
1338                spacing: 1.0,
1339                direction: $direction,
1340                language: "en".to_string(),
1341                script: "latin".to_string(),
1342                fn_: Some($fn),
1343            },
1344            children: Vec::new(),
1345        }
1346    };
1347    ($text:expr, $size:expr, $font:expr, fn=$fn:expr) => {
1348        Scad {
1349            op: ScadOp::Text {
1350                text: $text.to_string(),
1351                size: $size,
1352                font: $font.to_string(),
1353                halign: TextHalign::left,
1354                valign: TextValign::baseline,
1355                spacing: 1.0,
1356                direction: TextDirection::ltr,
1357                language: "en".to_string(),
1358                script: "latin".to_string(),
1359                fn_: Some($fn),
1360            },
1361            children: Vec::new(),
1362        }
1363    };
1364    ($text:expr, $size:expr, fn=$fn:expr) => {
1365        Scad {
1366            op: ScadOp::Text {
1367                text: $text.to_string(),
1368                size: $size,
1369                font: "Liberation Sans".to_string(),
1370                halign: TextHalign::left,
1371                valign: TextValign::baseline,
1372                spacing: 1.0,
1373                direction: TextDirection::ltr,
1374                language: "en".to_string(),
1375                script: "latin".to_string(),
1376                fn_: Some($fn),
1377            },
1378            children: Vec::new(),
1379        }
1380    };
1381    ($text:expr, fn=$fn:expr) => {
1382        Scad {
1383            op: ScadOp::Text {
1384                text: $text.to_string(),
1385                size: 10.0,
1386                font: "Liberation Sans".to_string(),
1387                halign: TextHalign::left,
1388                valign: TextValign::baseline,
1389                spacing: 1.0,
1390                direction: TextDirection::ltr,
1391                language: "en".to_string(),
1392                script: "latin".to_string(),
1393                fn_: Some($fn),
1394            },
1395            children: Vec::new(),
1396        }
1397    };
1398    ($text:expr, $size:expr, $font:expr, $halign:expr, $valign:expr, $direction:expr) => {
1399        Scad {
1400            op: ScadOp::Text {
1401                text: $text.to_string(),
1402                size: $size,
1403                font: $font.to_string(),
1404                halign: $halign,
1405                valign: $valign,
1406                spacing: 1.0,
1407                direction: $direction,
1408                language: "en".to_string(),
1409                script: "latin".to_string(),
1410                fn_: None,
1411            },
1412            children: Vec::new(),
1413        }
1414    };
1415    ($text:expr, $size:expr, $font:expr) => {
1416        Scad {
1417            op: ScadOp::Text {
1418                text: $text.to_string(),
1419                size: $size,
1420                font: $font.to_string(),
1421                halign: TextHalign::left,
1422                valign: TextValign::baseline,
1423                spacing: 1.0,
1424                direction: TextDirection::ltr,
1425                language: "en".to_string(),
1426                script: "latin".to_string(),
1427                fn_: None,
1428            },
1429            children: Vec::new(),
1430        }
1431    };
1432    ($text:expr, $size:expr) => {
1433        Scad {
1434            op: ScadOp::Text {
1435                text: $text.to_string(),
1436                size: $size,
1437                font: "Liberation Sans".to_string(),
1438                halign: TextHalign::left,
1439                valign: TextValign::baseline,
1440                spacing: 1.0,
1441                direction: TextDirection::ltr,
1442                language: "en".to_string(),
1443                script: "latin".to_string(),
1444                fn_: None,
1445            },
1446            children: Vec::new(),
1447        }
1448    };
1449    ($text:expr) => {
1450        Scad {
1451            op: ScadOp::Text {
1452                text: $text.to_string(),
1453                size: 10.0,
1454                font: "Liberation Sans".to_string(),
1455                halign: TextHalign::left,
1456                valign: TextValign::baseline,
1457                spacing: 1.0,
1458                direction: TextDirection::ltr,
1459                language: "en".to_string(),
1460                script: "latin".to_string(),
1461                fn_: None,
1462            },
1463            children: Vec::new(),
1464        }
1465    };
1466}
1467
1468/// Import a file for use in OpenSCAD
1469///
1470/// #params
1471///
1472/// file: The path of the file to import.
1473///
1474/// convexity: Number of outside faces a ray could encouter when passing through object. Preview only.
1475///
1476/// expansion: Scad struct literal.
1477///
1478/// #patterns
1479///
1480/// import!('file: &str');
1481///
1482/// import!('file: &str', 'convexity: u64');
1483#[macro_export]
1484macro_rules! import {
1485    ($file:expr) => {
1486        Scad {
1487            op: ScadOp::Import {
1488                file: $file.to_string(),
1489                convexity: 1,
1490            },
1491            children: Vec::new(),
1492        }
1493    };
1494    ($file:expr, $convexity:expr) => {
1495        Scad {
1496            op: ScadOp::Import {
1497                file: $file.to_string(),
1498                convexity: $convexity,
1499            },
1500            children: Vec::new(),
1501        }
1502    };
1503}
1504
1505/// Create a 2D projection of a 3D object.
1506///
1507/// #params
1508///
1509/// cut: When true the 2D shape is the part of the 3D object that is on the xy plane.
1510/// When false the 2D shape is the 'shadow' of the 3D object on the xy plane.
1511///
1512/// children: A list of 1 or more Scad structs separated by and ending with a semicolon.
1513///
1514/// expansion: Scad struct literal
1515///
1516/// #patterns
1517///
1518/// projection!('child: Scad'; ...;);
1519///
1520/// projection!(cut='cut: bool', 'child: Scad'; ...;);
1521#[macro_export]
1522macro_rules! projection {
1523  (cut=$cut:expr, $($child:expr);+;) => {
1524    Scad {
1525      op: ScadOp::Projection { cut: $cut },
1526      children: vec![$($child,)+],
1527    }
1528  };
1529  ($($child:expr);+;) => {
1530    Scad {
1531      op: ScadOp::Projection { cut: false },
1532      children: vec![$($child,)+],
1533    }
1534  };
1535}
1536
1537/// Creates a sphere.
1538///
1539/// #params
1540///
1541/// diameter: The diameter of the sphere.
1542///
1543/// radius: The radius of the sphere.
1544///
1545/// fa: The minimum angle between segments.
1546///
1547/// fs: The minimum length of a segment.
1548///
1549/// fn: The number of segments in the circle.
1550///
1551/// expansion: Scad struct literal.
1552///
1553/// #patterns
1554///
1555/// sphere!('radius: f64');
1556///
1557/// sphere!('radius: f64', fn='fn: u64');
1558///
1559/// sphere!('radius: f64', fa='fa: f64');
1560///
1561/// sphere!('radius: f64', fs='fs: f64');
1562///
1563/// sphere!('radius: f64', fa='fa: f64', fs='fs: f64');
1564///
1565/// sphere!(d='diameter: f64');
1566///
1567/// sphere!(d='diameter: f64', fn='fn: u64');
1568///
1569/// sphere!(d='diameter: f64', fa='fa: f64');
1570///
1571/// sphere!(d='diameter: f64', fs='fs: f64');
1572///
1573/// sphere!(d='diameter: f64', fa='fa: f64', fs='fs: f64');
1574///
1575/// sphere!(r='radius: f64');
1576///
1577/// sphere!(r='radius: f64', fn='fn: u64');
1578///
1579/// sphere!(r='radius: f64', fa='fa: f64');
1580///
1581/// sphere!(r='radius: f64', fs='fs: f64');
1582///
1583/// sphere!(r='radius: f64', fa='fa: f64', fs='fs: f64');
1584#[macro_export]
1585macro_rules! sphere {
1586    (d=$dia:expr) => {
1587        Scad {
1588            op: ScadOp::Sphere {
1589                radius: $dia / 2.0,
1590                fa: None,
1591                fs: None,
1592                fn_: None,
1593            },
1594            children: Vec::new(),
1595        }
1596    };
1597    (d=$dia:expr, fn=$fn:expr) => {
1598        Scad {
1599            op: ScadOp::Sphere {
1600                radius: $dia / 2.0,
1601                fa: None,
1602                fs: None,
1603                fn_: Some($fn),
1604            },
1605            children: Vec::new(),
1606        }
1607    };
1608    (d=$dia:expr, fa=$fa:expr) => {
1609        Scad {
1610            op: ScadOp::Sphere {
1611                radius: $dia / 2.0,
1612                fa: Some($fa),
1613                fs: None,
1614                fn_: None,
1615            },
1616            children: Vec::new(),
1617        }
1618    };
1619    (d=$dia:expr, fs=$fs:expr) => {
1620        Scad {
1621            op: ScadOp::Sphere {
1622                radius: $dia / 2.0,
1623                fa: None,
1624                fs: Some($fs),
1625                fn_: None,
1626            },
1627            children: Vec::new(),
1628        }
1629    };
1630    (d=$dia:expr, fa=$fa:expr, fs=$fs:expr) => {
1631        Scad {
1632            op: ScadOp::Sphere {
1633                radius: $dia / 2.0,
1634                fa: Some($fa),
1635                fs: Some($fs),
1636                fn_: None,
1637            },
1638            children: Vec::new(),
1639        }
1640    };
1641    (r=$r:expr) => {
1642        Scad {
1643            op: ScadOp::Sphere {
1644                radius: $r,
1645                fa: None,
1646                fs: None,
1647                fn_: None,
1648            },
1649            children: Vec::new(),
1650        }
1651    };
1652    (r=$r:expr, fn=$fn:expr) => {
1653        Scad {
1654            op: ScadOp::Sphere {
1655                radius: $r,
1656                fa: None,
1657                fs: None,
1658                fn_: Some($fn),
1659            },
1660            children: Vec::new(),
1661        }
1662    };
1663    (r=$r:expr, fa=$fa:expr) => {
1664        Scad {
1665            op: ScadOp::Sphere {
1666                radius: $r,
1667                fa: Some($fa),
1668                fs: None,
1669                fn_: None,
1670            },
1671            children: Vec::new(),
1672        }
1673    };
1674    (r=$r:expr, fs=$fs:expr) => {
1675        Scad {
1676            op: ScadOp::Sphere {
1677                radius: $r,
1678                fa: None,
1679                fs: Some($fs),
1680                fn_: None,
1681            },
1682            children: Vec::new(),
1683        }
1684    };
1685    (r=$r:expr, fa=$fa:expr, fs=$fs:expr) => {
1686        Scad {
1687            op: ScadOp::Sphere {
1688                radius: $r,
1689                fa: Some($fa),
1690                fs: Some($fs),
1691                fn_: None,
1692            },
1693            children: Vec::new(),
1694        }
1695    };
1696    ($r:expr, fa=$fa:expr) => {
1697        Scad {
1698            op: ScadOp::Sphere {
1699                radius: $r,
1700                fa: Some($fa),
1701                fs: None,
1702                fn_: None,
1703            },
1704            children: Vec::new(),
1705        }
1706    };
1707    ($r:expr, fs=$fs:expr) => {
1708        Scad {
1709            op: ScadOp::Sphere {
1710                radius: $r,
1711                fa: None,
1712                fs: Some($fs),
1713                fn_: None,
1714            },
1715            children: Vec::new(),
1716        }
1717    };
1718    ($r:expr, fa=$fa:expr, fs=$fs:expr) => {
1719        Scad {
1720            op: ScadOp::Sphere {
1721                radius: $r,
1722                fa: Some($fa),
1723                fs: Some($fs),
1724                fn_: None,
1725            },
1726            children: Vec::new(),
1727        }
1728    };
1729    ($r:expr) => {
1730        Scad {
1731            op: ScadOp::Sphere {
1732                radius: $r,
1733                fa: None,
1734                fs: None,
1735                fn_: None,
1736            },
1737            children: Vec::new(),
1738        }
1739    };
1740    ($r:expr, fn=$fn:expr) => {
1741        Scad {
1742            op: ScadOp::Sphere {
1743                radius: $r,
1744                fa: None,
1745                fs: None,
1746                fn_: Some($fn),
1747            },
1748            children: Vec::new(),
1749        }
1750    };
1751}
1752
1753/// Create a cube.
1754///
1755/// #params
1756///
1757/// size: The size of a side of the cube.
1758///
1759/// center: Whether to center the cube or leave in the first octant.
1760///
1761/// [x, y, z]: The dimensions of the cube.
1762///
1763/// expansion: Scad struct literal.
1764///
1765/// #patterns
1766///
1767/// cube!('size: f64');
1768///
1769/// cube!('size: f64', 'center: bool');
1770///
1771/// cube!(\['x: f64', 'y: f64', 'z: f64'\]);
1772///
1773/// cube!(\['x: f64', 'y: f64', 'z: f64'\], 'center: bool');
1774#[macro_export]
1775macro_rules! cube {
1776    ([$x:expr, $y:expr, $z:expr], $center:expr) => {
1777        Scad {
1778            op: ScadOp::Cube {
1779                size: Pt3::new($x, $y, $z),
1780                center: $center,
1781            },
1782            children: Vec::new(),
1783        }
1784    };
1785    ([$x:expr, $y:expr, $z:expr]) => {
1786        Scad {
1787            op: ScadOp::Cube {
1788                size: Pt3::new($x, $y, $z),
1789                center: false,
1790            },
1791            children: Vec::new(),
1792        }
1793    };
1794    ($size:expr, $center:expr) => {
1795        Scad {
1796            op: ScadOp::Cube {
1797                size: Pt3::new($size, $size, $size),
1798                center: $center,
1799            },
1800            children: Vec::new(),
1801        }
1802    };
1803    ($size:expr) => {
1804        Scad {
1805            op: ScadOp::Cube {
1806                size: Pt3::new($size, $size, $size),
1807                center: false,
1808            },
1809            children: Vec::new(),
1810        }
1811    };
1812}
1813
1814/// Creates a cylinder.
1815///
1816/// #params
1817///
1818/// height: The height of the cylinder.
1819///
1820/// radius: The radius of the cylinder.
1821///
1822/// radius1: The radius at the bottom.
1823///
1824/// radius2: The radius at the top.
1825///
1826/// diameter: The diameter of the cylinder.
1827///
1828/// diameter1: The diameter at the bottom.
1829///
1830/// diameter2: The diameter at the top.
1831///
1832/// center: When true the cylinder is centered at the world origin. When false the
1833/// cylinder 'sits' on the world origin.
1834///
1835/// fa: The minimum angle between segments.
1836///
1837/// fs: The minimum length of a segment.
1838///
1839/// fn: The number of segments in the cylinder.
1840///
1841/// expansion: Scad struct literal.
1842///
1843/// #patterns
1844///
1845/// cylinder!('height: f64', 'radius: f64')
1846///
1847/// cylinder!('height: f64', 'radius: f64', fn='fn: u64')
1848///
1849/// cylinder!('height: f64', 'radius1: f64', 'radius2: f64')
1850///
1851/// cylinder!('height: f64', 'radius1: f64', 'radius2: f64', 'center: bool')
1852///
1853/// cylinder!('height: f64', 'radius1: f64', 'radius2: f64', 'center: bool', fa='fa: f64')
1854///
1855/// cylinder!('height: f64', 'radius1: f64', 'radius2: f64', 'center: bool', fs='fs: f64')
1856///
1857/// cylinder!('height: f64', 'radius1: f64', 'radius2: f64', 'center: bool', fa='fa: f64', fs='fs: f64')
1858///
1859/// cylinder!('height: f64', 'radius1: f64', 'radius2: f64', 'center: bool', fn='fn: u64')
1860///
1861/// cylinder!('height: f64', d='diameter: f64')
1862///
1863/// cylinder!('height: f64', d1='diameter1: f64', d2='diameter2: f64')
1864///
1865/// cylinder!('height: f64', d1='diameter1: f64', d2='diameter2: f64', center='center: bool')
1866///
1867/// cylinder!('height: f64', d1='diameter1: f64', d2='diameter2: f64', center='center: bool', fa='fa: f64')
1868///
1869/// cylinder!('height: f64', d1='diameter1: f64', d2='diameter2: f64', center='center: bool', fs='fs: f64')
1870///
1871/// cylinder!('height: f64', d1='diameter1: f64', d2='diameter2: f64', center='center: bool', fa='fa: f64', fs='fs: f64')
1872///
1873/// cylinder!('height: f64', d1='diameter1: f64', d2='diameter2: f64', center='center: bool', fn='fn: u64')
1874///
1875/// cylinder!(h='height: f64', r='radius: f64')
1876///
1877/// cylinder!(h='height: f64', r1='radius1: f64', r2='radius2: f64')
1878///
1879/// cylinder!(h='height: f64', r1='radius1: f64', r2='radius2: f64', center='center: bool')
1880///
1881/// cylinder!(h='height: f64', r1='radius1: f64', r2='radius2: f64', center='center: bool', fa='fa: f64')
1882///
1883/// cylinder!(h='height: f64', r1='radius1: f64', r2='radius2: f64', center='center: bool', fs='fs: f64')
1884///
1885/// cylinder!(h='height: f64', r1='radius1: f64', r2='radius2: f64', center='center: bool', fa='fa: f64', fs='fs: f64')
1886///
1887/// cylinder!(h='height: f64', r1='radius1: f64', r2='radius2: f64', center='center: bool', fn='fn: u64')
1888///
1889/// cylinder!(h='height: f64', d='diameter: f64')
1890///
1891/// cylinder!(h='height: f64', d1='diameter1: f64', d2='diameter2: f64')
1892///
1893/// cylinder!(h='height: f64', d1='diameter1: f64', d2='diameter2: f64', center='center: bool')
1894///
1895/// cylinder!(h='height: f64', d1='diameter1: f64', d2='diameter2: f64', center='center: bool', fa='fa: f64')
1896///
1897/// cylinder!(h='height: f64', d1='diameter1: f64', d2='diameter2: f64', center='center: bool', fs='fs: f64')
1898///
1899/// cylinder!(h='height: f64', d1='diameter1: f64', d2='diameter2: f64', center='center: bool', fa='fa: f64', fs='fs: f64')
1900///
1901/// cylinder!(h='height: f64', d1='diameter1: f64', d2='diameter2: f64', center='center: bool', fn='fn: u64')
1902#[macro_export]
1903macro_rules! cylinder {
1904    (h=$height:expr, d1=$diameter1:expr, d2=$diameter2:expr, center=$center:expr, fa=$fa:expr, fs=$fs:expr) => {
1905        Scad {
1906            op: ScadOp::Cylinder {
1907                height: $height,
1908                radius1: $diameter1 / 2.0,
1909                radius2: $diameter2 / 2.0,
1910                center: $center,
1911                fa: Some($fa),
1912                fs: Some($fs),
1913                fn_: None,
1914            },
1915            children: Vec::new(),
1916        }
1917    };
1918    (h=$height:expr, d1=$diameter1:expr, d2=$diameter2:expr, center=$center:expr, fa=$fa:expr) => {
1919        Scad {
1920            op: ScadOp::Cylinder {
1921                height: $height,
1922                radius1: $diameter1 / 2.0,
1923                radius2: $diameter2 / 2.0,
1924                center: $center,
1925                fa: Some($fa),
1926                fs: None,
1927                fn_: None,
1928            },
1929            children: Vec::new(),
1930        }
1931    };
1932    (h=$height:expr, d1=$diameter1:expr, d2=$diameter2:expr, center=$center:expr, fs=$fs:expr) => {
1933        Scad {
1934            op: ScadOp::Cylinder {
1935                height: $height,
1936                radius1: $diameter1 / 2.0,
1937                radius2: $diameter2 / 2.0,
1938                center: $center,
1939                fa: None,
1940                fs: Some($fs),
1941                fn_: None,
1942            },
1943            children: Vec::new(),
1944        }
1945    };
1946    (h=$height:expr, d1=$diameter1:expr, d2=$diameter2:expr, center=$center:expr, fn=$fn:expr) => {
1947        Scad {
1948            op: ScadOp::Cylinder {
1949                height: $height,
1950                radius1: $diameter1 / 2.0,
1951                radius2: $diameter2 / 2.0,
1952                center: $center,
1953                fa: None,
1954                fs: None,
1955                fn_: Some($fn),
1956            },
1957            children: Vec::new(),
1958        }
1959    };
1960    (h=$height:expr, d1=$diameter1:expr, d2=$diameter2:expr, center=$center:expr) => {
1961        Scad {
1962            op: ScadOp::Cylinder {
1963                height: $height,
1964                radius1: $diameter1 / 2.0,
1965                radius2: $diameter2 / 2.0,
1966                center: $center,
1967                fa: None,
1968                fs: None,
1969                fn_: None,
1970            },
1971            children: Vec::new(),
1972        }
1973    };
1974    (h=$height:expr, d1=$diameter1:expr, d2=$diameter2:expr) => {
1975        Scad {
1976            op: ScadOp::Cylinder {
1977                height: $height,
1978                radius1: $diameter1 / 2.0,
1979                radius2: $diameter2 / 2.0,
1980                center: false,
1981                fa: None,
1982                fs: None,
1983                fn_: None,
1984            },
1985            children: Vec::new(),
1986        }
1987    };
1988    (h=$height:expr, d=$diameter:expr) => {
1989        Scad {
1990            op: ScadOp::Cylinder {
1991                height: $height,
1992                radius1: $diameter / 2.0,
1993                radius2: $diameter / 2.0,
1994                center: false,
1995                fa: None,
1996                fs: None,
1997                fn_: None,
1998            },
1999            children: Vec::new(),
2000        }
2001    };
2002    (h=$height:expr, r1=$radius1:expr, r2=$radius2:expr, center=$center:expr, fa=$fa:expr, fs=$fs:expr) => {
2003        Scad {
2004            op: ScadOp::Cylinder {
2005                height: $height,
2006                radius1: $radius1,
2007                radius2: $radius2,
2008                center: $center,
2009                fa: Some($fa),
2010                fs: Some($fs),
2011                fn_: None,
2012            },
2013            children: Vec::new(),
2014        }
2015    };
2016    (h=$height:expr, r1=$radius1:expr, r2=$radius2:expr, center=$center:expr, fa=$fa:expr) => {
2017        Scad {
2018            op: ScadOp::Cylinder {
2019                height: $height,
2020                radius1: $radius1,
2021                radius2: $radius2,
2022                center: $center,
2023                fa: Some($fa),
2024                fs: None,
2025                fn_: None,
2026            },
2027            children: Vec::new(),
2028        }
2029    };
2030    (h=$height:expr, r1=$radius1:expr, r2=$radius2:expr, center=$center:expr, fs=$fs:expr) => {
2031        Scad {
2032            op: ScadOp::Cylinder {
2033                height: $height,
2034                radius1: $radius1,
2035                radius2: $radius2,
2036                center: $center,
2037                fa: None,
2038                fs: Some($fs),
2039                fn_: None,
2040            },
2041            children: Vec::new(),
2042        }
2043    };
2044    (h=$height:expr, r1=$radius1:expr, r2=$radius2:expr, center=$center:expr, fn=$fn:expr) => {
2045        Scad {
2046            op: ScadOp::Cylinder {
2047                height: $height,
2048                radius1: $radius1,
2049                radius2: $radius2,
2050                center: $center,
2051                fa: None,
2052                fs: None,
2053                fn_: Some($fn),
2054            },
2055            children: Vec::new(),
2056        }
2057    };
2058    (h=$height:expr, r1=$radius1:expr, r2=$radius2:expr, center=$center:expr) => {
2059        Scad {
2060            op: ScadOp::Cylinder {
2061                height: $height,
2062                radius1: $radius1,
2063                radius2: $radius2,
2064                center: $center,
2065                fa: None,
2066                fs: None,
2067                fn_: None,
2068            },
2069            children: Vec::new(),
2070        }
2071    };
2072    (h=$height:expr, r1=$radius1:expr, r2=$radius2:expr) => {
2073        Scad {
2074            op: ScadOp::Cylinder {
2075                height: $height,
2076                radius1: $radius1,
2077                radius2: $radius2,
2078                center: false,
2079                fa: None,
2080                fs: None,
2081                fn_: None,
2082            },
2083            children: Vec::new(),
2084        }
2085    };
2086    (h=$height:expr, r=$radius:expr) => {
2087        Scad {
2088            op: ScadOp::Cylinder {
2089                height: $height,
2090                radius1: $radius,
2091                radius2: $radius,
2092                center: false,
2093                fa: None,
2094                fs: None,
2095                fn_: None,
2096            },
2097            children: Vec::new(),
2098        }
2099    };
2100    ($height:expr, d1=$diameter1:expr, d2=$diameter2:expr, center=$center:expr, fa=$fa:expr, fs=$fs:expr) => {
2101        Scad {
2102            op: ScadOp::Cylinder {
2103                height: $height,
2104                radius1: $diameter1 / 2.0,
2105                radius2: $diameter2 / 2.0,
2106                center: $center,
2107                fa: Some($fa),
2108                fs: Some($fs),
2109                fn_: None,
2110            },
2111            children: Vec::new(),
2112        }
2113    };
2114    ($height:expr, d1=$diameter1:expr, d2=$diameter2:expr, center=$center:expr, fa=$fa:expr) => {
2115        Scad {
2116            op: ScadOp::Cylinder {
2117                height: $height,
2118                radius1: $diameter1 / 2.0,
2119                radius2: $diameter2 / 2.0,
2120                center: $center,
2121                fa: Some($fa),
2122                fs: None,
2123                fn_: None,
2124            },
2125            children: Vec::new(),
2126        }
2127    };
2128    ($height:expr, d1=$diameter1:expr, d2=$diameter2:expr, center=$center:expr, fs=$fs:expr) => {
2129        Scad {
2130            op: ScadOp::Cylinder {
2131                height: $height,
2132                radius1: $diameter1 / 2.0,
2133                radius2: $diameter2 / 2.0,
2134                center: $center,
2135                fa: None,
2136                fs: Some($fs),
2137                fn_: None,
2138            },
2139            children: Vec::new(),
2140        }
2141    };
2142    ($height:expr, d1=$diameter1:expr, d2=$diameter2:expr, center=$center:expr, fn=$fn:expr) => {
2143        Scad {
2144            op: ScadOp::Cylinder {
2145                height: $height,
2146                radius1: $diameter1 / 2.0,
2147                radius2: $diameter2 / 2.0,
2148                center: $center,
2149                fa: None,
2150                fs: None,
2151                fn_: Some($fn),
2152            },
2153            children: Vec::new(),
2154        }
2155    };
2156    ($height:expr, d1=$diameter1:expr, d2=$diameter2:expr, center=$center:expr) => {
2157        Scad {
2158            op: ScadOp::Cylinder {
2159                height: $height,
2160                radius1: $diameter1 / 2.0,
2161                radius2: $diameter2 / 2.0,
2162                center: $center,
2163                fa: None,
2164                fs: None,
2165                fn_: None,
2166            },
2167            children: Vec::new(),
2168        }
2169    };
2170    ($height:expr, d1=$diameter1:expr, d2=$diameter2:expr) => {
2171        Scad {
2172            op: ScadOp::Cylinder {
2173                height: $height,
2174                radius1: $diameter1 / 2.0,
2175                radius2: $diameter2 / 2.0,
2176                center: false,
2177                fa: None,
2178                fs: None,
2179                fn_: None,
2180            },
2181            children: Vec::new(),
2182        }
2183    };
2184    ($height:expr, d=$diameter:expr) => {
2185        Scad {
2186            op: ScadOp::Cylinder {
2187                height: $height,
2188                radius1: $diameter / 2.0,
2189                radius2: $diameter / 2.0,
2190                center: false,
2191                fa: None,
2192                fs: None,
2193                fn_: None,
2194            },
2195            children: Vec::new(),
2196        }
2197    };
2198    ($height:expr, $radius1:expr, $radius2:expr, $center:expr, fa=$fa:expr, fs=$fs:expr) => {
2199        Scad {
2200            op: ScadOp::Cylinder {
2201                height: $height,
2202                radius1: $radius1,
2203                radius2: $radius2,
2204                center: $center,
2205                fa: Some($fa),
2206                fs: Some($fs),
2207                fn_: None,
2208            },
2209            children: Vec::new(),
2210        }
2211    };
2212    ($height:expr, $radius1:expr, $radius2:expr, $center:expr, fa=$fa:expr) => {
2213        Scad {
2214            op: ScadOp::Cylinder {
2215                height: $height,
2216                radius1: $radius1,
2217                radius2: $radius2,
2218                center: $center,
2219                fa: Some($fa),
2220                fs: None,
2221                fn_: None,
2222            },
2223            children: Vec::new(),
2224        }
2225    };
2226    ($height:expr, $radius1:expr, $radius2:expr, $center:expr, fs=$fs:expr) => {
2227        Scad {
2228            op: ScadOp::Cylinder {
2229                height: $height,
2230                radius1: $radius1,
2231                radius2: $radius2,
2232                center: $center,
2233                fa: None,
2234                fs: Some($fs),
2235                fn_: None,
2236            },
2237            children: Vec::new(),
2238        }
2239    };
2240    ($height:expr, $radius1:expr, $radius2:expr, $center:expr, fn=$fn:expr) => {
2241        Scad {
2242            op: ScadOp::Cylinder {
2243                height: $height,
2244                radius1: $radius1,
2245                radius2: $radius2,
2246                center: $center,
2247                fa: None,
2248                fs: None,
2249                fn_: Some($fn),
2250            },
2251            children: Vec::new(),
2252        }
2253    };
2254    ($height:expr, $radius1:expr, $radius2:expr, $center:expr) => {
2255        Scad {
2256            op: ScadOp::Cylinder {
2257                height: $height,
2258                radius1: $radius1,
2259                radius2: $radius2,
2260                center: $center,
2261                fa: None,
2262                fs: None,
2263                fn_: None,
2264            },
2265            children: Vec::new(),
2266        }
2267    };
2268    ($height:expr, $radius:expr, fn=$fn:expr) => {
2269        Scad {
2270            op: ScadOp::Cylinder {
2271                height: $height,
2272                radius1: $radius,
2273                radius2: $radius,
2274                center: false,
2275                fa: None,
2276                fs: None,
2277                fn_: Some($fn),
2278            },
2279            children: Vec::new(),
2280        }
2281    };
2282    ($height:expr, $radius1:expr, $radius2:expr) => {
2283        Scad {
2284            op: ScadOp::Cylinder {
2285                height: $height,
2286                radius1: $radius1,
2287                radius2: $radius2,
2288                center: false,
2289                fa: None,
2290                fs: None,
2291                fn_: None,
2292            },
2293            children: Vec::new(),
2294        }
2295    };
2296    ($height:expr, $radius:expr) => {
2297        Scad {
2298            op: ScadOp::Cylinder {
2299                height: $height,
2300                radius1: $radius,
2301                radius2: $radius,
2302                center: false,
2303                fa: None,
2304                fs: None,
2305                fn_: None,
2306            },
2307            children: Vec::new(),
2308        }
2309    };
2310}
2311
2312/// Creates a polyhedron.
2313///
2314/// #params
2315///
2316/// points: The vertices of the polyhedron.
2317///
2318/// faces: A list of lists of indices into points.
2319///
2320/// convexity: The number of outside faces a ray intersecting the polyhedron might encounter. Preview only.
2321///
2322/// expansion: A Scad struct literal.
2323///
2324/// #patterns
2325///
2326/// polyhedron!('points: Pt3s', 'faces: Faces');
2327///
2328/// polyhedron!('points: Pt3s', 'faces: Faces', 'convexity: u64');
2329///
2330/// polyhedron!(points='points: Pt3s', faces='faces: Faces', convexity='convexity: u64');
2331#[macro_export]
2332macro_rules! polyhedron {
2333    (points=$points:expr, faces=$faces:expr, convexity=$convexity:expr) => {
2334        Scad {
2335            op: ScadOp::Polyhedron {
2336                points: $points,
2337                faces: $faces,
2338                convexity: $convexity,
2339            },
2340            children: Vec::new(),
2341        }
2342    };
2343    ($points:expr, $faces:expr, $convexity:expr) => {
2344        Scad {
2345            op: ScadOp::Polyhedron {
2346                points: $points,
2347                faces: $faces,
2348                convexity: $convexity,
2349            },
2350            children: Vec::new(),
2351        }
2352    };
2353    ($points:expr, $faces:expr) => {
2354        Scad {
2355            op: ScadOp::Polyhedron {
2356                points: $points,
2357                faces: $faces,
2358                convexity: 1,
2359            },
2360            children: Vec::new(),
2361        }
2362    };
2363}
2364
2365/// Extrude a 2D profile along the Z axis creating a 3D shape.
2366///
2367/// #params
2368///
2369/// height: The height of the extrusion.
2370///
2371/// center: Centered on world origin or 'sitting' on world origin.
2372///
2373/// convexity: The number of outside faces a ray might encounter. Preview only.
2374///
2375/// twist: Degrees of rotation along the extrusion.
2376///
2377/// scale: Scale at the end of the extrusion. May have separate X and Y coordinates e.g. [1.5, 0.5].
2378///
2379/// slices: Resolution of the extrusion. Seems to have the same effect as $fn.
2380///
2381/// fn: Same as slices.
2382///
2383/// children: A list of Scad objects to apply the extrusion to. Separated and ending with a semicolon.
2384///
2385/// expansion: A Scad struct literal.
2386///
2387/// #patterns
2388///
2389/// linear_extrude!('height: f64', 'children: Scad';);
2390///
2391/// linear_extrude!(height='height: f64', center='center: bool', convexity='convexity: u64', twist='twist: f64', scale='scale: f64', slices='slices: u64', 'children: Scad';);
2392///
2393/// linear_extrude!(height='height: f64', center='center: bool', convexity='convexity: u64', twist='twist: f64', scale=\['scale_x: f64', 'scale_y: f64'\], slices='slices: u64', 'children: Scad';);
2394///
2395/// linear_extrude!(height='height: f64', center='center: bool', convexity='convexity: u64', twist='twist: f64', scale='scale: f64', fn='fn: u64', 'children: Scad';);
2396///
2397/// linear_extrude!(height='height: f64', center='center: bool', convexity='convexity: u64', twist='twist: f64', scale=\['scale_x: f64', 'scale_y: f64'\], fn='fn: u64', 'children: Scad';);
2398#[macro_export]
2399macro_rules! linear_extrude {
2400    (height=$height:expr, center=$center:expr, convexity=$convexity:expr, twist=$twist:expr, scale=[$scale_x:expr, $scale_y:expr], fn=$fn:expr, $($child:expr);+;) => {
2401        Scad {
2402            op: ScadOp::LinearExtrude {
2403                height: $height,
2404                center: $center,
2405                convexity: $convexity,
2406                twist: $twist,
2407                scale: Pt2::new($scale_x, $scale_y),
2408                slices: None,
2409                fn_: Some($fn),
2410            },
2411            children: vec![$($child,)+],
2412        }
2413    };
2414    (height=$height:expr, center=$center:expr, convexity=$convexity:expr, twist=$twist:expr, scale=[$scale_x:expr, $scale_y:expr], slices=$slices:expr, $($child:expr);+;) => {
2415        Scad {
2416            op: ScadOp::LinearExtrude {
2417                height: $height,
2418                center: $center,
2419                convexity: $convexity,
2420                twist: $twist,
2421                scale: Pt2::new($scale_x, $scale_y),
2422                slices: Some($slices),
2423                fn_: None,
2424            },
2425            children: vec![$($child,)+],
2426        }
2427    };
2428    (height=$height:expr, center=$center:expr, convexity=$convexity:expr, twist=$twist:expr, scale=$scale:expr, fn=$fn:expr, $($child:expr);+;) => {
2429        Scad {
2430            op: ScadOp::LinearExtrude {
2431                height: $height,
2432                center: $center,
2433                convexity: $convexity,
2434                twist: $twist,
2435                scale: Pt2::new($scale, $scale),
2436                slices: None,
2437                fn_: Some($fn),
2438            },
2439            children: vec![$($child,)+],
2440        }
2441    };
2442    (height=$height:expr, center=$center:expr, convexity=$convexity:expr, twist=$twist:expr, scale=$scale:expr, slices=$slices:expr, $($child:expr);+;) => {
2443        Scad {
2444            op: ScadOp::LinearExtrude {
2445                height: $height,
2446                center: $center,
2447                convexity: $convexity,
2448                twist: $twist,
2449                scale: Pt2::new($scale, $scale),
2450                slices: Some($slices),
2451                fn_: None,
2452            },
2453            children: vec![$($child,)+],
2454        }
2455    };
2456    ($height:expr, $($child:expr);+;) => {
2457        Scad {
2458            op: ScadOp::LinearExtrude {
2459                height: $height,
2460                center: false,
2461                convexity: 1,
2462                twist: 0.0,
2463                scale: Pt2::new(1.0,1.0),
2464                slices: None,
2465                fn_: None,
2466            },
2467            children: vec![$($child,)+],
2468        }
2469    };
2470}
2471
2472/// Create a 3D shape by rotating a 2D profile around the Z axis.
2473///
2474/// #params
2475///
2476/// angle: The angle in degrees to extrude through.
2477///
2478/// convexity: The number of outside faces a ray could pass through when intersecting the extrusion. Preview only.
2479///
2480/// fa: The minimum angle between segments.
2481///
2482/// fs: The minimum length of a segment.
2483///
2484/// fn: The number of segments in the cylinder.
2485///
2486/// children: A list of Scad objects to apply the extrusion to. Separated and ending with a semicolon.
2487///
2488/// expansion: A Scad struct literal.
2489///
2490/// rotate_extrude!('children: Scad';);
2491///
2492/// rotate_extrude!(angle='angle: f64', 'children: Scad';);
2493///
2494/// rotate_extrude!(angle='angle: f64', convexity='convexity: u64', 'children: Scad';);
2495///
2496/// rotate_extrude!(angle='angle: f64', convexity='convexity: u64', fa='fa: f64', 'children: Scad';);
2497///
2498/// rotate_extrude!(angle='angle: f64', convexity='convexity: u64', fs='fs: f64', 'children: Scad';);
2499///
2500/// rotate_extrude!(angle='angle: f64', convexity='convexity: u64', fa='fa: f64', fs='fs: f64', 'children: Scad';);
2501
2502/// rotate_extrude!(angle='angle: f64', convexity='convexity: u64', fn='fn: f64', 'children: Scad';);
2503#[macro_export]
2504macro_rules! rotate_extrude {
2505    (angle=$angle:expr, convexity=$convexity:expr, fn=$fn:expr, $($child:expr);+;) => {
2506        Scad {
2507            op: ScadOp::RotateExtrude {
2508                angle: $angle,
2509                convexity: $convexity,
2510                fa: None,
2511                fs: None,
2512                fn_: Some($fn),
2513            },
2514            children: vec![$($child,)+],
2515        }
2516    };
2517    (angle=$angle:expr, convexity=$convexity:expr, fa=$fa:expr, fs=$fs:expr, $($child:expr);+;) => {
2518        Scad {
2519            op: ScadOp::RotateExtrude {
2520                angle: $angle,
2521                convexity: $convexity,
2522                fa: Some($fa),
2523                fs: Some($fs),
2524                fn_: None,
2525            },
2526            children: vec![$($child,)+],
2527        }
2528    };
2529    (angle=$angle:expr, convexity=$convexity:expr, fs=$fs:expr, $($child:expr);+;) => {
2530        Scad {
2531            op: ScadOp::RotateExtrude {
2532                angle: $angle,
2533                convexity: $convexity,
2534                fa: None,
2535                fs: Some($fs),
2536                fn_: None,
2537            },
2538            children: vec![$($child,)+],
2539        }
2540    };
2541    (angle=$angle:expr, convexity=$convexity:expr, fa=$fa:expr, $($child:expr);+;) => {
2542        Scad {
2543            op: ScadOp::RotateExtrude {
2544                angle: $angle,
2545                convexity: $convexity,
2546                fa: Some($fa),
2547                fs: None,
2548                fn_: None,
2549            },
2550            children: vec![$($child,)+],
2551        }
2552    };
2553    (angle=$angle:expr, convexity=$convexity:expr, $($child:expr);+;) => {
2554        Scad {
2555            op: ScadOp::RotateExtrude {
2556                angle: $angle,
2557                convexity: $convexity,
2558                fa: None,
2559                fs: None,
2560                fn_: None,
2561            },
2562            children: vec![$($child,)+],
2563        }
2564    };
2565    (angle=$angle:expr, $($child:expr);+;) => {
2566        Scad {
2567            op: ScadOp::RotateExtrude {
2568                angle: $angle,
2569                convexity: 1,
2570                fa: None,
2571                fs: None,
2572                fn_: None,
2573            },
2574            children: vec![$($child,)+],
2575        }
2576    };
2577    ($($child:expr);+;) => {
2578        Scad {
2579            op: ScadOp::RotateExtrude {
2580                angle: 360.0,
2581                convexity: 1,
2582                fa: None,
2583                fs: None,
2584                fn_: None,
2585            },
2586            children: vec![$($child,)+],
2587        }
2588    };
2589}
2590
2591/// Loads a height map from a file.
2592///
2593/// #params
2594///
2595/// file: The path to the file to load.
2596///
2597/// center: Whether to center object or leave in first octant.
2598///
2599/// invert: Whether to invert the data.
2600///
2601/// convexity: The number of outside faces a ray could pass through when intersecting the object. Preview only.
2602///
2603/// expansion: A Scad struct literal.
2604///
2605/// #patterns
2606///
2607/// surface!('file: &str');
2608///
2609/// surface!(file='file: &str', center='center: bool', invert='invert: bool', convexity='convexity: u64');
2610#[macro_export]
2611macro_rules! surface {
2612    (file=$file:expr, center=$center:expr, invert=$invert:expr, convexity=$convexity:expr) => {
2613        Scad {
2614            op: ScadOp::Surface {
2615                file: $file.to_string(),
2616                center: $center,
2617                invert: $invert,
2618                convexity: $convexity,
2619            },
2620            children: Vec::new(),
2621        }
2622    };
2623    ($file:expr) => {
2624        Scad {
2625            op: ScadOp::Surface {
2626                file: $file.to_string(),
2627                center: false,
2628                invert: false,
2629                convexity: 1,
2630            },
2631            children: Vec::new(),
2632        }
2633    };
2634}
2635
2636/// Translates children.
2637///
2638/// #params
2639///
2640/// v: The x, y, and z coordinates to translate by e.g. [1.0, 2.0, 3.0].
2641///
2642/// children: A list of Scad objects separated and ending with a semicolon.
2643///
2644/// expansion: A Scad struct literal.
2645///
2646/// #patterns:
2647///
2648/// translate!(\['x: f64', 'y: f64', 'z: f64'\], 'children: Scad';);
2649///
2650/// translate!(v=\['x: f64', 'y: f64', 'z: f64'\], 'children: Scad';);
2651#[macro_export]
2652macro_rules! translate {
2653    (v=[$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2654        Scad {
2655            op: ScadOp::Translate {
2656                v: Pt3::new($x, $y, $z),
2657            },
2658            children: vec![$($child,)+],
2659        }
2660    };
2661    ([$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2662        Scad {
2663            op: ScadOp::Translate {
2664                v: Pt3::new($x, $y, $z),
2665            },
2666            children: vec![$($child,)+],
2667        }
2668    };
2669}
2670
2671/// Rotates children.
2672///
2673/// #params
2674///
2675/// a: Degrees of rotation around v when v is given else a vector of degrees for rotation around
2676/// the x, y, and z axis or a scalar for 2D rotations.
2677///
2678/// v: Axis to rotate around.
2679///
2680/// children: A list of Scad objects separated and ending with a semicolon.
2681///
2682/// expansion: A Scad struct literal.
2683///
2684/// #patterns
2685///
2686/// rotate!(\['x: f64', 'y: f64', 'z: f64'\], 'children: Scad';);
2687///
2688/// rotate!(a=\['x: f64', 'y: f64', 'z: f64'\], 'children: Scad';);
2689///
2690/// rotate!(a='z: f64', 'children: Scad';);
2691///
2692/// rotate!('z: f64', 'children: Scad';);
2693///
2694/// rotate!('a: f64, \['x: f64', 'y: f64', 'z: f64'\], 'children: Scad';);
2695
2696/// rotate!(a='a: f64, v=\['x: f64', 'y: f64', 'z: f64'\], 'children: Scad';);
2697#[macro_export]
2698macro_rules! rotate {
2699    (a=$a:expr, v=[$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2700        Scad {
2701            op: ScadOp::Rotate {
2702                a: Some($a),
2703                a_is_scalar: false,
2704                v: Pt3::new($x, $y, $z),
2705            },
2706            children: vec![$($child,)+],
2707        }
2708    };
2709    ($a:expr, [$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2710        Scad {
2711            op: ScadOp::Rotate {
2712                a: Some($a),
2713                a_is_scalar: false,
2714                v: Pt3::new($x, $y, $z),
2715            },
2716            children: vec![$($child,)+],
2717        }
2718    };
2719    (a=[$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2720        Scad {
2721            op: ScadOp::Rotate {
2722                a: None,
2723                a_is_scalar: false,
2724                v: Pt3::new($x, $y, $z),
2725            },
2726            children: vec![$($child,)+],
2727        }
2728    };
2729    ([$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2730        Scad {
2731            op: ScadOp::Rotate {
2732                a: None,
2733                a_is_scalar: false,
2734                v: Pt3::new($x, $y, $z),
2735            },
2736            children: vec![$($child,)+],
2737        }
2738    };
2739    (a=$a:expr, $($child:expr);+;) => {
2740        Scad {
2741            op: ScadOp::Rotate {
2742                a: Some($a),
2743                a_is_scalar: true,
2744                v: Pt3::new(0.0, 0.0, 0.0),
2745            },
2746            children: vec![$($child,)+],
2747        }
2748    };
2749    ($a:expr, $($child:expr);+;) => {
2750        Scad {
2751            op: ScadOp::Rotate {
2752                a: Some($a),
2753                a_is_scalar: true,
2754                v: Pt3::new(0.0, 0.0, 0.0),
2755            },
2756            children: vec![$($child,)+],
2757        }
2758    };
2759}
2760
2761/// Scale an object.
2762///
2763/// #params
2764///
2765/// v: Vector of scale factors for x, y, and z axis respectively.
2766///
2767/// children: A list of Scad objects separated and ending with a semicolon.
2768///
2769/// expansion: A Scad struct literal.
2770///
2771/// #patterns
2772///
2773/// scale!(\['x: f64', 'y: f64', 'z: f64'\], 'children: Scad';);
2774///
2775/// scale!(v=\['x: f64', 'y: f64', 'z: f64'\], 'children: Scad';);
2776#[macro_export]
2777macro_rules! scale {
2778    (v=[$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2779        Scad {
2780            op: ScadOp::Scale {
2781                v: Pt3::new($x, $y, $z),
2782            },
2783            children: vec![$($child,)+],
2784        }
2785    };
2786    ([$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2787        Scad {
2788            op: ScadOp::Scale {
2789                v: Pt3::new($x, $y, $z),
2790            },
2791            children: vec![$($child,)+],
2792        }
2793    };
2794}
2795
2796/// Resize an object.
2797///
2798/// #params
2799///
2800/// newsize: The new x, y, and z dimensions.
2801///
2802/// auto: When true zero's in newsize will scale the proportionaltely to the given axis. Auto can be a vector
2803/// of three bools to exclude an axis from the auto.
2804///
2805/// convexity: The number of outside edges a ray might encounter when passing through the object.
2806///
2807/// children: A list of Scad objects separated and ending with a semicolon.
2808///
2809/// expansion: A Scad struct literal.
2810///
2811/// #patterns
2812///
2813/// resize!(\['x: f64', 'y: f64', 'z: f64'\], 'children: Scad';);
2814///
2815/// resize!(\['x: f64', 'y: f64', 'z: f64'\], 'auto: bool', 'children: Scad';);
2816///
2817/// resize!(\['x: f64', 'y: f64', 'z: f64'\], \['auto_x: bool', 'auto_y: bool', 'auto_z: bool'\], 'children: Scad';);
2818///
2819/// resize!(\['x: f64', 'y: f64', 'z: f64'\], 'auto: bool', 'convexity: u64', 'children: Scad';);
2820///
2821/// resize!(\['x: f64', 'y: f64', 'z: f64'\], \['auto_x: bool', 'auto_y: bool', 'auto_z: bool'\], 'convexity: u64', 'children: Scad';);
2822#[macro_export]
2823macro_rules! resize {
2824    (newsize=[$x:expr, $y:expr, $z:expr], auto=[$auto_x:expr, $auto_y:expr, $auto_z:expr], convexity=$convexity:expr, $($child:expr);+;) => {
2825        Scad {
2826            op: ScadOp::Resize {
2827                newsize: Pt3::new($x, $y, $z),
2828                auto: false,
2829                auto_is_vec: true,
2830                autovec: ($auto_x, $auto_y, $auto_z),
2831                convexity: $convexity,
2832            },
2833            children: vec![$($child,)+],
2834        }
2835    };
2836    (newsize=[$x:expr, $y:expr, $z:expr], auto=$auto:expr, convexity=$convexity:expr, $($child:expr);+;) => {
2837        Scad {
2838            op: ScadOp::Resize {
2839                newsize: Pt3::new($x, $y, $z),
2840                auto: $auto,
2841                auto_is_vec: false,
2842                autovec: (false, false, false),
2843                convexity: $convexity,
2844            },
2845            children: vec![$($child,)+],
2846        }
2847    };
2848    (newsize=[$x:expr, $y:expr, $z:expr], auto=[$auto_x:expr, $auto_y:expr, $auto_z:expr], $($child:expr);+;) => {
2849        Scad {
2850            op: ScadOp::Resize {
2851                newsize: Pt3::new($x, $y, $z),
2852                auto: false,
2853                auto_is_vec: true,
2854                autovec: ($auto_x, $auto_y, $auto_z),
2855                convexity: 1,
2856            },
2857            children: vec![$($child,)+],
2858        }
2859    };
2860    (newsize=[$x:expr, $y:expr, $z:expr], auto=$auto:expr, $($child:expr);+;) => {
2861        Scad {
2862            op: ScadOp::Resize {
2863                newsize: Pt3::new($x, $y, $z),
2864                auto: $auto,
2865                auto_is_vec: false,
2866                autovec: (false, false, false),
2867                convexity: 1,
2868            },
2869            children: vec![$($child,)+],
2870        }
2871    };
2872    (newsize=[$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2873        Scad {
2874            op: ScadOp::Resize {
2875                newsize: Pt3::new($x, $y, $z),
2876                auto: false,
2877                auto_is_vec: false,
2878                autovec: (false, false, false),
2879                convexity: 1,
2880            },
2881            children: vec![$($child,)+],
2882        }
2883    };
2884    ([$x:expr, $y:expr, $z:expr], [$auto_x:expr, $auto_y:expr, $auto_z:expr], $convexity:expr, $($child:expr);+;) => {
2885        Scad {
2886            op: ScadOp::Resize {
2887                newsize: Pt3::new($x, $y, $z),
2888                auto: false,
2889                auto_is_vec: true,
2890                autovec: ($auto_x, $auto_y, $auto_z),
2891                convexity: $convexity,
2892            },
2893            children: vec![$($child,)+],
2894        }
2895    };
2896    ([$x:expr, $y:expr, $z:expr], $auto:expr, $convexity:expr, $($child:expr);+;) => {
2897        Scad {
2898            op: ScadOp::Resize {
2899                newsize: Pt3::new($x, $y, $z),
2900                auto: $auto,
2901                auto_is_vec: false,
2902                autovec: (false, false, false),
2903                convexity: $convexity,
2904            },
2905            children: vec![$($child,)+],
2906        }
2907    };
2908    ([$x:expr, $y:expr, $z:expr], [$auto_x:expr, $auto_y:expr, $auto_z:expr], $($child:expr);+;) => {
2909        Scad {
2910            op: ScadOp::Resize {
2911                newsize: Pt3::new($x, $y, $z),
2912                auto: false,
2913                auto_is_vec: true,
2914                autovec: ($auto_x, $auto_y, $auto_z),
2915                convexity: 1,
2916            },
2917            children: vec![$($child,)+],
2918        }
2919    };
2920    ([$x:expr, $y:expr, $z:expr], $auto:expr, $($child:expr);+;) => {
2921        Scad {
2922            op: ScadOp::Resize {
2923                newsize: Pt3::new($x, $y, $z),
2924                auto: $auto,
2925                auto_is_vec: false,
2926                autovec: (false, false, false),
2927                convexity: 1,
2928            },
2929            children: vec![$($child,)+],
2930        }
2931    };
2932    ([$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2933        Scad {
2934            op: ScadOp::Resize {
2935                newsize: Pt3::new($x, $y, $z),
2936                auto: false,
2937                auto_is_vec: false,
2938                autovec: (false, false, false),
2939                convexity: 1,
2940            },
2941            children: vec![$($child,)+],
2942        }
2943    };
2944}
2945
2946/// Mirror object(s).
2947///
2948/// #params
2949///
2950/// v: Normal of the mirror plane.
2951///
2952/// children: A list of Scad objects separated and ending with a semicolon.
2953///
2954/// expansion: A Scad struct literal.
2955///
2956/// #patterns
2957///
2958/// mirror!(\['x: f64', 'y: f64', 'z: f64'\], 'children: Scad';);
2959///
2960/// mirror!(v=\['x: f64', 'y: f64', 'z: f64'\], 'children: Scad';);
2961#[macro_export]
2962macro_rules! mirror {
2963    (v=[$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2964        Scad {
2965            op: ScadOp::Mirror {
2966                v: Pt3::new($x, $y, $z),
2967            },
2968            children: vec![$($child,)+],
2969        }
2970    };
2971    ([$x:expr, $y:expr, $z:expr], $($child:expr);+;) => {
2972        Scad {
2973            op: ScadOp::Mirror {
2974                v: Pt3::new($x, $y, $z),
2975            },
2976            children: vec![$($child,)+],
2977        }
2978    };
2979}
2980
2981/// Colors children.
2982///
2983/// #params
2984///
2985/// [r, g, b, a]: 4 floats between 0.0 and 1.0 for red, green, blue, and alpha.
2986///
2987/// "#rrggbbaa": &str hex code.
2988///
2989/// c: ScadColor enum member.
2990///
2991/// alpha: The alpha channel for c.
2992///
2993/// children: A list of Scad objects separated and ending with a semicolon.
2994///
2995/// expansion: A Scad struct literal.
2996///
2997/// #patterns
2998///
2999/// color!(\['r: f64', 'g: f64', 'b: f64', 'a: f64'\], 'children: Scad';);
3000///
3001/// color!('"#rrggbbaa": &str', 'children: Scad';);
3002///
3003/// color!(c='c: ScadColor', 'children: Scad';);
3004///
3005/// color!(c='c: ScadColor', alpha='alpha: f64', 'children: Scad';);
3006#[macro_export]
3007macro_rules! color {
3008    (c=$color:expr, alpha=$alpha:expr, $($child:expr);+;) => {
3009        Scad {
3010            op: ScadOp::Color {
3011                rgba: None,
3012                color: Some($color),
3013                hex: None,
3014                alpha: Some($alpha),
3015            },
3016            children: vec![$($child,)+],
3017        }
3018    };
3019    (c=$color:expr, $($child:expr);+;) => {
3020        Scad {
3021            op: ScadOp::Color {
3022                rgba: None,
3023                color: Some($color),
3024                hex: None,
3025                alpha: None,
3026            },
3027            children: vec![$($child,)+],
3028        }
3029    };
3030    ([$r:expr, $g:expr, $b:expr, $a:expr], $($child:expr);+;) => {
3031        Scad {
3032            op: ScadOp::Color {
3033                rgba: Some(Pt4::new($r, $g, $b, $a)),
3034                color: None,
3035                hex: None,
3036                alpha: None,
3037            },
3038            children: vec![$($child,)+],
3039        }
3040    };
3041    ($hex:expr, $($child:expr);+;) => {
3042        Scad {
3043            op: ScadOp::Color {
3044                rgba: None,
3045                color: None,
3046                hex: Some($hex.to_string()),
3047                alpha: None,
3048            },
3049            children: vec![$($child,)+],
3050        }
3051    };
3052}
3053
3054/// Offsets a 2D shape.
3055///
3056/// #params
3057///
3058/// r: The radius of the offset.
3059///
3060/// delta: Used instead of r for sharp corners.
3061///
3062/// chamfer: Whether to extend a corner to a point (false) or chamfer it (true).
3063///
3064/// children: A list of Scad objects separated and ending with a semicolon.
3065///
3066/// expansion: A Scad struct literal.
3067///
3068/// #patterns
3069///
3070/// offset!('r: f64', 'children: Scad';);
3071///
3072/// offset!(delta='delta: f64', chamfer='chamfer: bool', 'children: Scad';);
3073#[macro_export]
3074macro_rules! offset {
3075    (delta=$delta:expr, chamfer=$chamfer:expr, $($child:expr);+;) => {
3076        Scad {
3077            op: ScadOp::Offset {
3078                r: None,
3079                delta: Some($delta),
3080                chamfer: $chamfer,
3081            },
3082            children: vec![$($child,)+],
3083        }
3084    };
3085    ($r:expr, $($child:expr);+;) => {
3086        Scad {
3087            op: ScadOp::Offset {
3088                r: Some($r),
3089                delta: None,
3090                chamfer: false,
3091            },
3092            children: vec![$($child,)+],
3093        }
3094    };
3095}
3096
3097/// Constructive Solid Geometry hull operation.
3098///
3099/// Combines multiple shapes into one.
3100///
3101/// #params
3102///
3103/// Scad structs seperated by and ending with a seimicolon.
3104#[macro_export]
3105macro_rules! hull {
3106  ($($child:expr);+;) => {
3107    Scad {
3108        op: ScadOp::Hull,
3109        children: vec![$($child,)+],
3110    }
3111  };
3112}
3113
3114/// Minkowski sum.
3115///
3116/// #params
3117///
3118/// convexity: The number of outside edges a ray might encounter when passing through the object.
3119///
3120/// children: A list of Scad objects separated and ending with a semicolon.
3121///
3122/// expansion: A Scad struct literal.
3123///
3124/// #patterns
3125///
3126/// minkowski!('children: Scad';);
3127///
3128/// minkowski!('convexity: u64', 'children: Scad';);
3129#[macro_export]
3130macro_rules! minkowski {
3131  ($convexity:expr, $($child:expr);+;) => {
3132    Scad {
3133        op: ScadOp::Minkowski {
3134            convexity: $convexity
3135        },
3136        children: vec![$($child,)+],
3137    }
3138  };
3139  ($($child:expr);+;) => {
3140    Scad {
3141        op: ScadOp::Minkowski {
3142            convexity:1
3143        },
3144        children: vec![$($child,)+],
3145    }
3146  };
3147}
3148/***********************************************************
3149* TESTING 1, 2, 3...
3150***********************************************************/
3151
3152#[cfg(test)]
3153mod tests {
3154    use crate::prelude::*;
3155    #[test]
3156    fn union_of_1() {
3157        let res = union!(circle!(1.0););
3158        assert!(
3159            res == Scad {
3160                op: ScadOp::Union,
3161                children: vec![Scad {
3162                    op: ScadOp::Circle {
3163                        radius: 1.0,
3164                        fa: None,
3165                        fs: None,
3166                        fn_: None,
3167                    },
3168                    children: Vec::new(),
3169                }],
3170            }
3171        );
3172    }
3173
3174    #[test]
3175    fn union_of_2() {
3176        let res = union!(circle!(1.0);square!(1.0););
3177        assert!(
3178            res == Scad {
3179                op: ScadOp::Union,
3180                children: vec![
3181                    Scad {
3182                        op: ScadOp::Circle {
3183                            radius: 1.0,
3184                            fa: None,
3185                            fs: None,
3186                            fn_: None,
3187                        },
3188                        children: Vec::new(),
3189                    },
3190                    Scad {
3191                        op: ScadOp::Square {
3192                            size: Pt2::new(1.0, 1.0),
3193                            center: false,
3194                        },
3195                        children: Vec::new(),
3196                    }
3197                ],
3198            }
3199        );
3200    }
3201
3202    #[test]
3203    fn difference_of_2() {
3204        let res = difference!(circle!(1.0);square!(1.0););
3205        assert!(
3206            res == Scad {
3207                op: ScadOp::Difference,
3208                children: vec![
3209                    Scad {
3210                        op: ScadOp::Circle {
3211                            radius: 1.0,
3212                            fa: None,
3213                            fs: None,
3214                            fn_: None,
3215                        },
3216                        children: Vec::new(),
3217                    },
3218                    Scad {
3219                        op: ScadOp::Square {
3220                            size: Pt2::new(1.0, 1.0),
3221                            center: false
3222                        },
3223                        children: Vec::new(),
3224                    }
3225                ],
3226            }
3227        );
3228    }
3229
3230    #[test]
3231    fn intersection_of_2() {
3232        let res = intersection!(circle!(1.0);square!(1.0););
3233        assert!(
3234            res == Scad {
3235                op: ScadOp::Intersection,
3236                children: vec![
3237                    Scad {
3238                        op: ScadOp::Circle {
3239                            radius: 1.0,
3240                            fa: None,
3241                            fs: None,
3242                            fn_: None,
3243                        },
3244                        children: Vec::new(),
3245                    },
3246                    Scad {
3247                        op: ScadOp::Square {
3248                            size: Pt2::new(1.0, 1.0),
3249                            center: false,
3250                        },
3251                        children: Vec::new(),
3252                    }
3253                ],
3254            }
3255        );
3256    }
3257
3258    #[test]
3259    fn circle_from_nradius() {
3260        let circle = circle!(r = 2.0);
3261        assert!(
3262            circle
3263                == Scad {
3264                    op: ScadOp::Circle {
3265                        radius: 2.0,
3266                        fa: None,
3267                        fs: None,
3268                        fn_: None,
3269                    },
3270                    children: Vec::new()
3271                }
3272        )
3273    }
3274
3275    #[test]
3276    fn circle_from_nradius_fn() {
3277        let circle = circle!(r=2.0, fn=4);
3278        assert!(
3279            circle
3280                == Scad {
3281                    op: ScadOp::Circle {
3282                        radius: 2.0,
3283                        fa: None,
3284                        fs: None,
3285                        fn_: Some(4)
3286                    },
3287                    children: Vec::new()
3288                }
3289        )
3290    }
3291
3292    #[test]
3293    fn circle_from_radius() {
3294        let circle = circle!(2.0);
3295        assert!(
3296            circle
3297                == Scad {
3298                    op: ScadOp::Circle {
3299                        radius: 2.0,
3300                        fa: None,
3301                        fs: None,
3302                        fn_: None,
3303                    },
3304                    children: Vec::new()
3305                }
3306        )
3307    }
3308
3309    #[test]
3310    fn circle_from_radius_fn() {
3311        let circle = circle!(2.0, fn=4);
3312        assert!(
3313            circle
3314                == Scad {
3315                    op: ScadOp::Circle {
3316                        radius: 2.0,
3317                        fa: None,
3318                        fs: None,
3319                        fn_: Some(4),
3320                    },
3321                    children: Vec::new(),
3322                }
3323        )
3324    }
3325
3326    #[test]
3327    fn circle_from_radius_fa() {
3328        let circle = circle!(2.0, fa = 4.0);
3329        assert!(
3330            circle
3331                == Scad {
3332                    op: ScadOp::Circle {
3333                        radius: 2.0,
3334                        fa: Some(4.0),
3335                        fs: None,
3336                        fn_: None,
3337                    },
3338                    children: Vec::new(),
3339                }
3340        )
3341    }
3342
3343    #[test]
3344    fn circle_from_radius_fs() {
3345        let circle = circle!(2.0, fs = 4.0);
3346        assert!(
3347            circle
3348                == Scad {
3349                    op: ScadOp::Circle {
3350                        radius: 2.0,
3351                        fa: None,
3352                        fs: Some(4.0),
3353                        fn_: None,
3354                    },
3355                    children: Vec::new(),
3356                }
3357        )
3358    }
3359
3360    #[test]
3361    fn circle_from_radius_fa_fs() {
3362        let circle = circle!(2.0, fa = 2.0, fs = 4.0);
3363        assert!(
3364            circle
3365                == Scad {
3366                    op: ScadOp::Circle {
3367                        radius: 2.0,
3368                        fa: Some(2.0),
3369                        fs: Some(4.0),
3370                        fn_: None,
3371                    },
3372                    children: Vec::new(),
3373                }
3374        )
3375    }
3376
3377    #[test]
3378    fn circle_from_nradius_fa() {
3379        let circle = circle!(r = 2.0, fa = 4.0);
3380        assert!(
3381            circle
3382                == Scad {
3383                    op: ScadOp::Circle {
3384                        radius: 2.0,
3385                        fa: Some(4.0),
3386                        fs: None,
3387                        fn_: None,
3388                    },
3389                    children: Vec::new(),
3390                }
3391        )
3392    }
3393
3394    #[test]
3395    fn circle_from_nradius_fs() {
3396        let circle = circle!(r = 2.0, fs = 4.0);
3397        assert!(
3398            circle
3399                == Scad {
3400                    op: ScadOp::Circle {
3401                        radius: 2.0,
3402                        fa: None,
3403                        fs: Some(4.0),
3404                        fn_: None,
3405                    },
3406                    children: Vec::new(),
3407                }
3408        )
3409    }
3410
3411    #[test]
3412    fn circle_from_nradius_fa_fs() {
3413        let circle = circle!(r = 2.0, fa = 2.0, fs = 4.0);
3414        assert!(
3415            circle
3416                == Scad {
3417                    op: ScadOp::Circle {
3418                        radius: 2.0,
3419                        fa: Some(2.0),
3420                        fs: Some(4.0),
3421                        fn_: None,
3422                    },
3423                    children: Vec::new(),
3424                }
3425        )
3426    }
3427
3428    #[test]
3429    fn circle_from_diameter() {
3430        let circle = circle!(d = 2.0);
3431        assert!(
3432            circle
3433                == Scad {
3434                    op: ScadOp::Circle {
3435                        radius: 1.0,
3436                        fa: None,
3437                        fs: None,
3438                        fn_: None,
3439                    },
3440                    children: Vec::new()
3441                }
3442        )
3443    }
3444
3445    #[test]
3446    fn circle_from_diameter_fn() {
3447        let circle = circle!(d = 2.0, fn=4);
3448        assert!(
3449            circle
3450                == Scad {
3451                    op: ScadOp::Circle {
3452                        radius: 1.0,
3453                        fa: None,
3454                        fs: None,
3455                        fn_: Some(4),
3456                    },
3457                    children: Vec::new()
3458                }
3459        )
3460    }
3461
3462    #[test]
3463    fn circle_from_diameter_fa() {
3464        let circle = circle!(d = 2.0, fa = 4.0);
3465        assert!(
3466            circle
3467                == Scad {
3468                    op: ScadOp::Circle {
3469                        radius: 1.0,
3470                        fa: Some(4.0),
3471                        fs: None,
3472                        fn_: None,
3473                    },
3474                    children: Vec::new()
3475                }
3476        )
3477    }
3478
3479    #[test]
3480    fn circle_from_diameter_fs() {
3481        let circle = circle!(d = 2.0, fs = 4.0);
3482        assert!(
3483            circle
3484                == Scad {
3485                    op: ScadOp::Circle {
3486                        radius: 1.0,
3487                        fa: None,
3488                        fs: Some(4.0),
3489                        fn_: None,
3490                    },
3491                    children: Vec::new()
3492                }
3493        )
3494    }
3495
3496    #[test]
3497    fn circle_from_diameter_fa_fs() {
3498        let circle = circle!(d = 2.0, fa = 2.0, fs = 4.0);
3499        assert!(
3500            circle
3501                == Scad {
3502                    op: ScadOp::Circle {
3503                        radius: 1.0,
3504                        fa: Some(2.0),
3505                        fs: Some(4.0),
3506                        fn_: None,
3507                    },
3508                    children: Vec::new()
3509                }
3510        )
3511    }
3512
3513    #[test]
3514    fn square_from_size() {
3515        let square = square!(10.0);
3516        assert!(
3517            square
3518                == Scad {
3519                    op: ScadOp::Square {
3520                        size: Pt2::new(10.0, 10.0),
3521                        center: false
3522                    },
3523                    children: Vec::new(),
3524                }
3525        )
3526    }
3527
3528    #[test]
3529    fn square_from_size_center() {
3530        let square = square!(10.0, true);
3531        assert!(
3532            square
3533                == Scad {
3534                    op: ScadOp::Square {
3535                        size: Pt2::new(10.0, 10.0),
3536                        center: true,
3537                    },
3538                    children: Vec::new(),
3539                }
3540        )
3541    }
3542
3543    #[test]
3544    fn square_from_point_literal() {
3545        let square = square!([10.0, 10.0]);
3546        assert!(
3547            square
3548                == Scad {
3549                    op: ScadOp::Square {
3550                        size: Pt2::new(10.0, 10.0),
3551                        center: false,
3552                    },
3553                    children: Vec::new(),
3554                }
3555        )
3556    }
3557
3558    #[test]
3559    fn square_from_point_literal_center() {
3560        let square = square!([10.0, 10.0], true);
3561        assert!(
3562            square
3563                == Scad {
3564                    op: ScadOp::Square {
3565                        size: Pt2::new(10.0, 10.0),
3566                        center: true,
3567                    },
3568                    children: Vec::new(),
3569                }
3570        )
3571    }
3572
3573    #[test]
3574    fn polygon_from_points() {
3575        let points = Pt2s::from_pt2s(vec![
3576            Pt2::new(0.0, 0.0),
3577            Pt2::new(1.0, 1.0),
3578            Pt2::new(2.0, 2.0),
3579        ]);
3580        let polygon = polygon!(points.clone());
3581        assert!(
3582            polygon
3583                == Scad {
3584                    op: ScadOp::Polygon {
3585                        points,
3586                        paths: None,
3587                        convexity: 1
3588                    },
3589                    children: Vec::new(),
3590                }
3591        )
3592    }
3593
3594    #[test]
3595    fn polygon_from_points_paths() {
3596        let points = Pt2s::from_pt2s(vec![
3597            Pt2::new(0.0, 0.0),
3598            Pt2::new(1.0, 1.0),
3599            Pt2::new(2.0, 2.0),
3600            Pt2::new(3.0, 3.0),
3601            Pt2::new(4.0, 4.0),
3602            Pt2::new(5.0, 5.0),
3603        ]);
3604        let paths = Paths::from_paths(vec![
3605            Indices::from_indices(vec![0, 1, 2]),
3606            Indices::from_indices(vec![3, 4, 5]),
3607        ]);
3608        let polygon = polygon!(points.clone(), paths.clone());
3609        assert!(
3610            polygon
3611                == Scad {
3612                    op: ScadOp::Polygon {
3613                        points,
3614                        paths: Some(paths),
3615                        convexity: 1
3616                    },
3617                    children: Vec::new(),
3618                }
3619        )
3620    }
3621
3622    #[test]
3623    fn polygon_from_points_paths_convexity() {
3624        let points = Pt2s::from_pt2s(vec![
3625            Pt2::new(0.0, 0.0),
3626            Pt2::new(1.0, 1.0),
3627            Pt2::new(2.0, 2.0),
3628            Pt2::new(3.0, 3.0),
3629            Pt2::new(4.0, 4.0),
3630            Pt2::new(5.0, 5.0),
3631        ]);
3632        let paths = Paths::from_paths(vec![
3633            Indices::from_indices(vec![0, 1, 2]),
3634            Indices::from_indices(vec![3, 4, 5]),
3635        ]);
3636        let polygon = polygon!(points.clone(), paths.clone(), 2);
3637        assert!(
3638            polygon
3639                == Scad {
3640                    op: ScadOp::Polygon {
3641                        points,
3642                        paths: Some(paths),
3643                        convexity: 2
3644                    },
3645                    children: Vec::new(),
3646                }
3647        )
3648    }
3649
3650    #[test]
3651    fn polygon_from_points_convexity() {
3652        let points = Pt2s::from_pt2s(vec![
3653            Pt2::new(0.0, 0.0),
3654            Pt2::new(1.0, 1.0),
3655            Pt2::new(2.0, 2.0),
3656        ]);
3657        let polygon = polygon!(points.clone(), convexity = 2);
3658        assert!(
3659            polygon
3660                == Scad {
3661                    op: ScadOp::Polygon {
3662                        points,
3663                        paths: None,
3664                        convexity: 2
3665                    },
3666                    children: Vec::new(),
3667                }
3668        )
3669    }
3670
3671    #[test]
3672    fn text_from_string() {
3673        let text = text!("Text");
3674        assert!(
3675            text == Scad {
3676                op: ScadOp::Text {
3677                    text: "Text".to_string(),
3678                    size: 10.0,
3679                    font: "Liberation Sans".to_string(),
3680                    halign: TextHalign::left,
3681                    valign: TextValign::baseline,
3682                    spacing: 1.0,
3683                    direction: TextDirection::ltr,
3684                    language: "en".to_string(),
3685                    script: "latin".to_string(),
3686                    fn_: None,
3687                },
3688                children: Vec::new(),
3689            }
3690        )
3691    }
3692
3693    #[test]
3694    fn text_from_string_size() {
3695        let text = text!("Text", 20.0);
3696        assert!(
3697            text == Scad {
3698                op: ScadOp::Text {
3699                    text: "Text".to_string(),
3700                    size: 20.0,
3701                    font: "Liberation Sans".to_string(),
3702                    halign: TextHalign::left,
3703                    valign: TextValign::baseline,
3704                    spacing: 1.0,
3705                    direction: TextDirection::ltr,
3706                    language: "en".to_string(),
3707                    script: "latin".to_string(),
3708                    fn_: None,
3709                },
3710                children: Vec::new(),
3711            }
3712        )
3713    }
3714
3715    #[test]
3716    fn text_from_string_size_font() {
3717        let text = text!("Text", 20.0, "Courier New");
3718        assert!(
3719            text == Scad {
3720                op: ScadOp::Text {
3721                    text: "Text".to_string(),
3722                    size: 20.0,
3723                    font: "Courier New".to_string(),
3724                    halign: TextHalign::left,
3725                    valign: TextValign::baseline,
3726                    spacing: 1.0,
3727                    direction: TextDirection::ltr,
3728                    language: "en".to_string(),
3729                    script: "latin".to_string(),
3730                    fn_: None,
3731                },
3732                children: Vec::new(),
3733            }
3734        )
3735    }
3736
3737    #[test]
3738    fn text_from_string_fn() {
3739        let text = text!("Text", fn=20);
3740        assert!(
3741            text == Scad {
3742                op: ScadOp::Text {
3743                    text: "Text".to_string(),
3744                    size: 10.0,
3745                    font: "Liberation Sans".to_string(),
3746                    halign: TextHalign::left,
3747                    valign: TextValign::baseline,
3748                    spacing: 1.0,
3749                    direction: TextDirection::ltr,
3750                    language: "en".to_string(),
3751                    script: "latin".to_string(),
3752                    fn_: Some(20),
3753                },
3754                children: Vec::new(),
3755            }
3756        )
3757    }
3758
3759    #[test]
3760    fn text_from_string_size_fn() {
3761        let text = text!("Text", 20.0, fn=20);
3762        assert!(
3763            text == Scad {
3764                op: ScadOp::Text {
3765                    text: "Text".to_string(),
3766                    size: 20.0,
3767                    font: "Liberation Sans".to_string(),
3768                    halign: TextHalign::left,
3769                    valign: TextValign::baseline,
3770                    spacing: 1.0,
3771                    direction: TextDirection::ltr,
3772                    language: "en".to_string(),
3773                    script: "latin".to_string(),
3774                    fn_: Some(20),
3775                },
3776                children: Vec::new(),
3777            }
3778        )
3779    }
3780
3781    #[test]
3782    fn text_from_string_size_font_fn() {
3783        let text = text!("Text", 20.0, "Courier New", fn=20);
3784        assert!(
3785            text == Scad {
3786                op: ScadOp::Text {
3787                    text: "Text".to_string(),
3788                    size: 20.0,
3789                    font: "Courier New".to_string(),
3790                    halign: TextHalign::left,
3791                    valign: TextValign::baseline,
3792                    spacing: 1.0,
3793                    direction: TextDirection::ltr,
3794                    language: "en".to_string(),
3795                    script: "latin".to_string(),
3796                    fn_: Some(20),
3797                },
3798                children: Vec::new(),
3799            }
3800        )
3801    }
3802
3803    #[test]
3804    fn text_from_string_size_font_halign_valign_direction() {
3805        let text = text!(
3806            "Text",
3807            20.0,
3808            "Courier New",
3809            TextHalign::center,
3810            TextValign::center,
3811            TextDirection::ttb
3812        );
3813        assert!(
3814            text == Scad {
3815                op: ScadOp::Text {
3816                    text: "Text".to_string(),
3817                    size: 20.0,
3818                    font: "Courier New".to_string(),
3819                    halign: TextHalign::center,
3820                    valign: TextValign::center,
3821                    spacing: 1.0,
3822                    direction: TextDirection::ttb,
3823                    language: "en".to_string(),
3824                    script: "latin".to_string(),
3825                    fn_: None,
3826                },
3827                children: Vec::new(),
3828            }
3829        )
3830    }
3831
3832    #[test]
3833    fn text_from_string_size_font_halign_valign_direction_fn() {
3834        let text = text!(
3835          "Text",
3836          20.0,
3837          "Courier New",
3838          TextHalign::center,
3839          TextValign::center,
3840          TextDirection::ttb,
3841          fn=20
3842        );
3843        assert!(
3844            text == Scad {
3845                op: ScadOp::Text {
3846                    text: "Text".to_string(),
3847                    size: 20.0,
3848                    font: "Courier New".to_string(),
3849                    halign: TextHalign::center,
3850                    valign: TextValign::center,
3851                    spacing: 1.0,
3852                    direction: TextDirection::ttb,
3853                    language: "en".to_string(),
3854                    script: "latin".to_string(),
3855                    fn_: Some(20),
3856                },
3857                children: Vec::new(),
3858            }
3859        )
3860    }
3861
3862    #[test]
3863    fn text_from_all_params() {
3864        let text = text!(
3865            "Text",
3866            20.0,
3867            "Courier New",
3868            TextHalign::center,
3869            TextValign::center,
3870            2.0,
3871            TextDirection::ttb,
3872            "en",
3873            "latin",
3874            20
3875        );
3876        assert!(
3877            text == Scad {
3878                op: ScadOp::Text {
3879                    text: "Text".to_string(),
3880                    size: 20.0,
3881                    font: "Courier New".to_string(),
3882                    halign: TextHalign::center,
3883                    valign: TextValign::center,
3884                    spacing: 2.0,
3885                    direction: TextDirection::ttb,
3886                    language: "en".to_string(),
3887                    script: "latin".to_string(),
3888                    fn_: Some(20),
3889                },
3890                children: Vec::new(),
3891            }
3892        )
3893    }
3894
3895    #[test]
3896    fn text_from_text_params() {
3897        let text_params = TextParams::default();
3898        let text = text!(text_params = text_params);
3899        assert!(
3900            text == Scad {
3901                op: ScadOp::Text {
3902                    text: "".to_string(),
3903                    size: 10.0,
3904                    font: "Liberation Sans".to_string(),
3905                    halign: TextHalign::left,
3906                    valign: TextValign::baseline,
3907                    spacing: 1.0,
3908                    direction: TextDirection::ltr,
3909                    language: "en".to_string(),
3910                    script: "latin".to_string(),
3911                    fn_: None,
3912                },
3913                children: Vec::new(),
3914            }
3915        )
3916    }
3917
3918    #[test]
3919    fn import_from_file() {
3920        let import = import!("monkey");
3921        assert!(
3922            import
3923                == Scad {
3924                    op: ScadOp::Import {
3925                        file: "monkey".to_string(),
3926                        convexity: 1
3927                    },
3928                    children: Vec::new(),
3929                }
3930        )
3931    }
3932
3933    #[test]
3934    fn import_from_file_convexity() {
3935        let import = import!("monkey", 3);
3936        assert!(
3937            import
3938                == Scad {
3939                    op: ScadOp::Import {
3940                        file: "monkey".to_string(),
3941                        convexity: 3
3942                    },
3943                    children: Vec::new(),
3944                }
3945        )
3946    }
3947
3948    #[test]
3949    fn projection_from_child() {
3950        let res = projection!(square!(10.0););
3951        assert!(
3952            res == Scad {
3953                op: ScadOp::Projection { cut: false },
3954                children: vec![Scad {
3955                    op: ScadOp::Square {
3956                        size: Pt2::new(10.0, 10.0),
3957                        center: false
3958                    },
3959                    children: Vec::new()
3960                }]
3961            }
3962        )
3963    }
3964
3965    #[test]
3966    fn projection_from_children() {
3967        let res = projection!(square!(10.0);circle!(10.0););
3968        assert!(
3969            res == Scad {
3970                op: ScadOp::Projection { cut: false },
3971                children: vec![
3972                    Scad {
3973                        op: ScadOp::Square {
3974                            size: Pt2::new(10.0, 10.0),
3975                            center: false
3976                        },
3977                        children: Vec::new()
3978                    },
3979                    Scad {
3980                        op: ScadOp::Circle {
3981                            radius: 10.0,
3982                            fa: None,
3983                            fs: None,
3984                            fn_: None,
3985                        },
3986                        children: Vec::new(),
3987                    }
3988                ]
3989            }
3990        )
3991    }
3992
3993    #[test]
3994    fn projection_from_cut_child() {
3995        let res = projection!(cut=true,square!(10.0););
3996        assert!(
3997            res == Scad {
3998                op: ScadOp::Projection { cut: true },
3999                children: vec![Scad {
4000                    op: ScadOp::Square {
4001                        size: Pt2::new(10.0, 10.0),
4002                        center: false
4003                    },
4004                    children: Vec::new()
4005                }]
4006            }
4007        )
4008    }
4009
4010    #[test]
4011    fn projection_from_cut_children() {
4012        let res = projection!(cut=true,square!(10.0);circle!(10.0););
4013        assert!(
4014            res == Scad {
4015                op: ScadOp::Projection { cut: true },
4016                children: vec![
4017                    Scad {
4018                        op: ScadOp::Square {
4019                            size: Pt2::new(10.0, 10.0),
4020                            center: false
4021                        },
4022                        children: Vec::new()
4023                    },
4024                    Scad {
4025                        op: ScadOp::Circle {
4026                            radius: 10.0,
4027                            fa: None,
4028                            fs: None,
4029                            fn_: None,
4030                        },
4031                        children: Vec::new(),
4032                    }
4033                ]
4034            }
4035        )
4036    }
4037
4038    #[test]
4039    fn sphere_from_nradius() {
4040        let sphere = sphere!(r = 2.0);
4041        assert!(
4042            sphere
4043                == Scad {
4044                    op: ScadOp::Sphere {
4045                        radius: 2.0,
4046                        fa: None,
4047                        fs: None,
4048                        fn_: None,
4049                    },
4050                    children: Vec::new()
4051                }
4052        )
4053    }
4054
4055    #[test]
4056    fn sphere_from_nradius_fn() {
4057        let sphere = sphere!(r=2.0, fn=4);
4058        assert!(
4059            sphere
4060                == Scad {
4061                    op: ScadOp::Sphere {
4062                        radius: 2.0,
4063                        fa: None,
4064                        fs: None,
4065                        fn_: Some(4)
4066                    },
4067                    children: Vec::new()
4068                }
4069        )
4070    }
4071
4072    #[test]
4073    fn sphere_from_radius() {
4074        let sphere = sphere!(2.0);
4075        assert!(
4076            sphere
4077                == Scad {
4078                    op: ScadOp::Sphere {
4079                        radius: 2.0,
4080                        fa: None,
4081                        fs: None,
4082                        fn_: None,
4083                    },
4084                    children: Vec::new()
4085                }
4086        )
4087    }
4088
4089    #[test]
4090    fn sphere_from_radius_fn() {
4091        let sphere = sphere!(2.0, fn=4);
4092        assert!(
4093            sphere
4094                == Scad {
4095                    op: ScadOp::Sphere {
4096                        radius: 2.0,
4097                        fa: None,
4098                        fs: None,
4099                        fn_: Some(4),
4100                    },
4101                    children: Vec::new(),
4102                }
4103        )
4104    }
4105
4106    #[test]
4107    fn sphere_from_radius_fa() {
4108        let sphere = sphere!(2.0, fa = 4.0);
4109        assert!(
4110            sphere
4111                == Scad {
4112                    op: ScadOp::Sphere {
4113                        radius: 2.0,
4114                        fa: Some(4.0),
4115                        fs: None,
4116                        fn_: None,
4117                    },
4118                    children: Vec::new(),
4119                }
4120        )
4121    }
4122
4123    #[test]
4124    fn sphere_from_radius_fs() {
4125        let sphere = sphere!(2.0, fs = 4.0);
4126        assert!(
4127            sphere
4128                == Scad {
4129                    op: ScadOp::Sphere {
4130                        radius: 2.0,
4131                        fa: None,
4132                        fs: Some(4.0),
4133                        fn_: None,
4134                    },
4135                    children: Vec::new(),
4136                }
4137        )
4138    }
4139
4140    #[test]
4141    fn sphere_from_radius_fa_fs() {
4142        let sphere = sphere!(2.0, fa = 2.0, fs = 4.0);
4143        assert!(
4144            sphere
4145                == Scad {
4146                    op: ScadOp::Sphere {
4147                        radius: 2.0,
4148                        fa: Some(2.0),
4149                        fs: Some(4.0),
4150                        fn_: None,
4151                    },
4152                    children: Vec::new(),
4153                }
4154        )
4155    }
4156
4157    #[test]
4158    fn sphere_from_nradius_fa() {
4159        let sphere = sphere!(r = 2.0, fa = 4.0);
4160        assert!(
4161            sphere
4162                == Scad {
4163                    op: ScadOp::Sphere {
4164                        radius: 2.0,
4165                        fa: Some(4.0),
4166                        fs: None,
4167                        fn_: None,
4168                    },
4169                    children: Vec::new(),
4170                }
4171        )
4172    }
4173
4174    #[test]
4175    fn sphere_from_nradius_fs() {
4176        let sphere = sphere!(r = 2.0, fs = 4.0);
4177        assert!(
4178            sphere
4179                == Scad {
4180                    op: ScadOp::Sphere {
4181                        radius: 2.0,
4182                        fa: None,
4183                        fs: Some(4.0),
4184                        fn_: None,
4185                    },
4186                    children: Vec::new(),
4187                }
4188        )
4189    }
4190
4191    #[test]
4192    fn sphere_from_nradius_fa_fs() {
4193        let sphere = sphere!(r = 2.0, fa = 2.0, fs = 4.0);
4194        assert!(
4195            sphere
4196                == Scad {
4197                    op: ScadOp::Sphere {
4198                        radius: 2.0,
4199                        fa: Some(2.0),
4200                        fs: Some(4.0),
4201                        fn_: None,
4202                    },
4203                    children: Vec::new(),
4204                }
4205        )
4206    }
4207
4208    #[test]
4209    fn sphere_from_diameter() {
4210        let sphere = sphere!(d = 2.0);
4211        assert!(
4212            sphere
4213                == Scad {
4214                    op: ScadOp::Sphere {
4215                        radius: 1.0,
4216                        fa: None,
4217                        fs: None,
4218                        fn_: None,
4219                    },
4220                    children: Vec::new()
4221                }
4222        )
4223    }
4224
4225    #[test]
4226    fn sphere_from_diameter_fn() {
4227        let sphere = sphere!(d = 2.0, fn=4);
4228        assert!(
4229            sphere
4230                == Scad {
4231                    op: ScadOp::Sphere {
4232                        radius: 1.0,
4233                        fa: None,
4234                        fs: None,
4235                        fn_: Some(4),
4236                    },
4237                    children: Vec::new()
4238                }
4239        )
4240    }
4241
4242    #[test]
4243    fn sphere_from_diameter_fa() {
4244        let sphere = sphere!(d = 2.0, fa = 4.0);
4245        assert!(
4246            sphere
4247                == Scad {
4248                    op: ScadOp::Sphere {
4249                        radius: 1.0,
4250                        fa: Some(4.0),
4251                        fs: None,
4252                        fn_: None,
4253                    },
4254                    children: Vec::new()
4255                }
4256        )
4257    }
4258
4259    #[test]
4260    fn sphere_from_diameter_fs() {
4261        let sphere = sphere!(d = 2.0, fs = 4.0);
4262        assert!(
4263            sphere
4264                == Scad {
4265                    op: ScadOp::Sphere {
4266                        radius: 1.0,
4267                        fa: None,
4268                        fs: Some(4.0),
4269                        fn_: None,
4270                    },
4271                    children: Vec::new()
4272                }
4273        )
4274    }
4275
4276    #[test]
4277    fn sphere_from_diameter_fa_fs() {
4278        let sphere = sphere!(d = 2.0, fa = 2.0, fs = 4.0);
4279        assert!(
4280            sphere
4281                == Scad {
4282                    op: ScadOp::Sphere {
4283                        radius: 1.0,
4284                        fa: Some(2.0),
4285                        fs: Some(4.0),
4286                        fn_: None,
4287                    },
4288                    children: Vec::new()
4289                }
4290        )
4291    }
4292
4293    #[test]
4294    fn cube_from_size() {
4295        let cube = cube!(10.0);
4296        assert!(
4297            cube == Scad {
4298                op: ScadOp::Cube {
4299                    size: Pt3::new(10.0, 10.0, 10.0),
4300                    center: false,
4301                },
4302                children: Vec::new(),
4303            }
4304        )
4305    }
4306
4307    #[test]
4308    fn cube_from_size_center() {
4309        let cube = cube!(10.0, true);
4310        assert!(
4311            cube == Scad {
4312                op: ScadOp::Cube {
4313                    size: Pt3::new(10.0, 10.0, 10.0),
4314                    center: true,
4315                },
4316                children: Vec::new(),
4317            }
4318        )
4319    }
4320
4321    #[test]
4322    fn cube_from_point() {
4323        let cube = cube!([10.0, 9.0, 8.0]);
4324        assert!(
4325            cube == Scad {
4326                op: ScadOp::Cube {
4327                    size: Pt3::new(10.0, 9.0, 8.0),
4328                    center: false,
4329                },
4330                children: Vec::new(),
4331            }
4332        )
4333    }
4334
4335    #[test]
4336    fn cube_from_point_center() {
4337        let cube = cube!([1.0, 2.0, 3.0], true);
4338        assert!(
4339            cube == Scad {
4340                op: ScadOp::Cube {
4341                    size: Pt3::new(1.0, 2.0, 3.0),
4342                    center: true,
4343                },
4344                children: Vec::new(),
4345            }
4346        )
4347    }
4348
4349    #[test]
4350    fn cylinder_from_height_radius() {
4351        let cylinder = cylinder!(12.0, 2.0);
4352        assert!(
4353            cylinder
4354                == Scad {
4355                    op: ScadOp::Cylinder {
4356                        height: 12.0,
4357                        radius1: 2.0,
4358                        radius2: 2.0,
4359                        center: false,
4360                        fa: None,
4361                        fs: None,
4362                        fn_: None,
4363                    },
4364                    children: Vec::new(),
4365                }
4366        )
4367    }
4368
4369    #[test]
4370    fn cylinder_from_height_radius1_radius2() {
4371        let cylinder = cylinder!(12.0, 2.0, 1.0);
4372        assert!(
4373            cylinder
4374                == Scad {
4375                    op: ScadOp::Cylinder {
4376                        height: 12.0,
4377                        radius1: 2.0,
4378                        radius2: 1.0,
4379                        center: false,
4380                        fa: None,
4381                        fs: None,
4382                        fn_: None,
4383                    },
4384                    children: Vec::new(),
4385                }
4386        )
4387    }
4388
4389    #[test]
4390    fn cylinder_from_height_radius1_radius2_center() {
4391        let cylinder = cylinder!(12.0, 2.0, 1.0, true);
4392        assert!(
4393            cylinder
4394                == Scad {
4395                    op: ScadOp::Cylinder {
4396                        height: 12.0,
4397                        radius1: 2.0,
4398                        radius2: 1.0,
4399                        center: true,
4400                        fa: None,
4401                        fs: None,
4402                        fn_: None,
4403                    },
4404                    children: Vec::new(),
4405                }
4406        )
4407    }
4408    #[test]
4409    fn cylinder_from_height_radius1_radius2_center_fa() {
4410        let cylinder = cylinder!(12.0, 2.0, 1.0, true, fa = 4.0);
4411        assert!(
4412            cylinder
4413                == Scad {
4414                    op: ScadOp::Cylinder {
4415                        height: 12.0,
4416                        radius1: 2.0,
4417                        radius2: 1.0,
4418                        center: true,
4419                        fa: Some(4.0),
4420                        fs: None,
4421                        fn_: None,
4422                    },
4423                    children: Vec::new(),
4424                }
4425        )
4426    }
4427    #[test]
4428    fn cylinder_from_height_radius1_radius2_center_fs() {
4429        let cylinder = cylinder!(12.0, 2.0, 1.0, true, fs = 0.25);
4430        assert!(
4431            cylinder
4432                == Scad {
4433                    op: ScadOp::Cylinder {
4434                        height: 12.0,
4435                        radius1: 2.0,
4436                        radius2: 1.0,
4437                        center: true,
4438                        fa: None,
4439                        fs: Some(0.25),
4440                        fn_: None,
4441                    },
4442                    children: Vec::new(),
4443                }
4444        )
4445    }
4446    #[test]
4447    fn cylinder_from_height_radius1_radius2_center_fa_fs() {
4448        let cylinder = cylinder!(12.0, 2.0, 1.0, true, fa = 2.0, fs = 0.1);
4449        assert!(
4450            cylinder
4451                == Scad {
4452                    op: ScadOp::Cylinder {
4453                        height: 12.0,
4454                        radius1: 2.0,
4455                        radius2: 1.0,
4456                        center: true,
4457                        fa: Some(2.0),
4458                        fs: Some(0.1),
4459                        fn_: None,
4460                    },
4461                    children: Vec::new(),
4462                }
4463        )
4464    }
4465    #[test]
4466    fn cylinder_from_height_radius1_radius2_center_fn() {
4467        let cylinder = cylinder!(12.0, 2.0, 1.0, true, fn=12);
4468        assert!(
4469            cylinder
4470                == Scad {
4471                    op: ScadOp::Cylinder {
4472                        height: 12.0,
4473                        radius1: 2.0,
4474                        radius2: 1.0,
4475                        center: true,
4476                        fa: None,
4477                        fs: None,
4478                        fn_: Some(12),
4479                    },
4480                    children: Vec::new(),
4481                }
4482        )
4483    }
4484
4485    #[test]
4486    fn cylinder_from_height_diameter() {
4487        let cylinder = cylinder!(12.0, d = 2.0);
4488        assert!(
4489            cylinder
4490                == Scad {
4491                    op: ScadOp::Cylinder {
4492                        height: 12.0,
4493                        radius1: 1.0,
4494                        radius2: 1.0,
4495                        center: false,
4496                        fa: None,
4497                        fs: None,
4498                        fn_: None,
4499                    },
4500                    children: Vec::new(),
4501                }
4502        )
4503    }
4504
4505    #[test]
4506    fn cylinder_from_height_diameter1_diameter2() {
4507        let cylinder = cylinder!(12.0, d1 = 4.0, d2 = 2.0);
4508        assert!(
4509            cylinder
4510                == Scad {
4511                    op: ScadOp::Cylinder {
4512                        height: 12.0,
4513                        radius1: 2.0,
4514                        radius2: 1.0,
4515                        center: false,
4516                        fa: None,
4517                        fs: None,
4518                        fn_: None,
4519                    },
4520                    children: Vec::new(),
4521                }
4522        )
4523    }
4524
4525    #[test]
4526    fn cylinder_from_height_diameter1_diameter2_center() {
4527        let cylinder = cylinder!(12.0, d1 = 2.0, d2 = 1.0, center = true);
4528        assert!(
4529            cylinder
4530                == Scad {
4531                    op: ScadOp::Cylinder {
4532                        height: 12.0,
4533                        radius1: 1.0,
4534                        radius2: 0.5,
4535                        center: true,
4536                        fa: None,
4537                        fs: None,
4538                        fn_: None,
4539                    },
4540                    children: Vec::new(),
4541                }
4542        )
4543    }
4544    #[test]
4545    fn cylinder_from_height_diameter1_diameter2_center_fa() {
4546        let cylinder = cylinder!(12.0, d1 = 4.0, d2 = 2.0, center = true, fa = 4.0);
4547        assert!(
4548            cylinder
4549                == Scad {
4550                    op: ScadOp::Cylinder {
4551                        height: 12.0,
4552                        radius1: 2.0,
4553                        radius2: 1.0,
4554                        center: true,
4555                        fa: Some(4.0),
4556                        fs: None,
4557                        fn_: None,
4558                    },
4559                    children: Vec::new(),
4560                }
4561        )
4562    }
4563    #[test]
4564    fn cylinder_from_height_diameter1_diameter2_center_fs() {
4565        let cylinder = cylinder!(12.0, d1 = 4.0, d2 = 2.0, center = true, fs = 0.25);
4566        assert!(
4567            cylinder
4568                == Scad {
4569                    op: ScadOp::Cylinder {
4570                        height: 12.0,
4571                        radius1: 2.0,
4572                        radius2: 1.0,
4573                        center: true,
4574                        fa: None,
4575                        fs: Some(0.25),
4576                        fn_: None,
4577                    },
4578                    children: Vec::new(),
4579                }
4580        )
4581    }
4582    #[test]
4583    fn cylinder_from_height_diameter1_diameter2_center_fa_fs() {
4584        let cylinder = cylinder!(12.0, d1 = 2.0, d2 = 1.0, center = true, fa = 2.0, fs = 0.1);
4585        assert!(
4586            cylinder
4587                == Scad {
4588                    op: ScadOp::Cylinder {
4589                        height: 12.0,
4590                        radius1: 1.0,
4591                        radius2: 0.5,
4592                        center: true,
4593                        fa: Some(2.0),
4594                        fs: Some(0.1),
4595                        fn_: None,
4596                    },
4597                    children: Vec::new(),
4598                }
4599        )
4600    }
4601    #[test]
4602    fn cylinder_from_height_diameter1_diameter2_center_fn() {
4603        let cylinder = cylinder!(12.0, d1=2.0, d2=1.0, center=true, fn=12);
4604        assert!(
4605            cylinder
4606                == Scad {
4607                    op: ScadOp::Cylinder {
4608                        height: 12.0,
4609                        radius1: 1.0,
4610                        radius2: 0.5,
4611                        center: true,
4612                        fa: None,
4613                        fs: None,
4614                        fn_: Some(12),
4615                    },
4616                    children: Vec::new(),
4617                }
4618        )
4619    }
4620
4621    #[test]
4622    fn cylinder_from_nheight_radius() {
4623        let cylinder = cylinder!(h = 12.0, r = 2.0);
4624        assert!(
4625            cylinder
4626                == Scad {
4627                    op: ScadOp::Cylinder {
4628                        height: 12.0,
4629                        radius1: 2.0,
4630                        radius2: 2.0,
4631                        center: false,
4632                        fa: None,
4633                        fs: None,
4634                        fn_: None,
4635                    },
4636                    children: Vec::new(),
4637                }
4638        )
4639    }
4640
4641    #[test]
4642    fn cylinder_from_nheight_radius1_radius2() {
4643        let cylinder = cylinder!(h = 12.0, r1 = 2.0, r2 = 1.0);
4644        assert!(
4645            cylinder
4646                == Scad {
4647                    op: ScadOp::Cylinder {
4648                        height: 12.0,
4649                        radius1: 2.0,
4650                        radius2: 1.0,
4651                        center: false,
4652                        fa: None,
4653                        fs: None,
4654                        fn_: None,
4655                    },
4656                    children: Vec::new(),
4657                }
4658        )
4659    }
4660
4661    #[test]
4662    fn cylinder_from_nheight_radius1_radius2_center() {
4663        let cylinder = cylinder!(h = 12.0, r1 = 2.0, r2 = 1.0, center = true);
4664        assert!(
4665            cylinder
4666                == Scad {
4667                    op: ScadOp::Cylinder {
4668                        height: 12.0,
4669                        radius1: 2.0,
4670                        radius2: 1.0,
4671                        center: true,
4672                        fa: None,
4673                        fs: None,
4674                        fn_: None,
4675                    },
4676                    children: Vec::new(),
4677                }
4678        )
4679    }
4680    #[test]
4681    fn cylinder_from_nheight_radius1_radius2_center_fa() {
4682        let cylinder = cylinder!(h = 12.0, r1 = 2.0, r2 = 1.0, center = true, fa = 4.0);
4683        assert!(
4684            cylinder
4685                == Scad {
4686                    op: ScadOp::Cylinder {
4687                        height: 12.0,
4688                        radius1: 2.0,
4689                        radius2: 1.0,
4690                        center: true,
4691                        fa: Some(4.0),
4692                        fs: None,
4693                        fn_: None,
4694                    },
4695                    children: Vec::new(),
4696                }
4697        )
4698    }
4699    #[test]
4700    fn cylinder_from_nheight_radius1_radius2_center_fs() {
4701        let cylinder = cylinder!(h = 12.0, r1 = 2.0, r2 = 1.0, center = true, fs = 0.25);
4702        assert!(
4703            cylinder
4704                == Scad {
4705                    op: ScadOp::Cylinder {
4706                        height: 12.0,
4707                        radius1: 2.0,
4708                        radius2: 1.0,
4709                        center: true,
4710                        fa: None,
4711                        fs: Some(0.25),
4712                        fn_: None,
4713                    },
4714                    children: Vec::new(),
4715                }
4716        )
4717    }
4718    #[test]
4719    fn cylinder_from_nheight_radius1_radius2_center_fa_fs() {
4720        let cylinder = cylinder!(
4721            h = 12.0,
4722            r1 = 2.0,
4723            r2 = 1.0,
4724            center = true,
4725            fa = 2.0,
4726            fs = 0.1
4727        );
4728        assert!(
4729            cylinder
4730                == Scad {
4731                    op: ScadOp::Cylinder {
4732                        height: 12.0,
4733                        radius1: 2.0,
4734                        radius2: 1.0,
4735                        center: true,
4736                        fa: Some(2.0),
4737                        fs: Some(0.1),
4738                        fn_: None,
4739                    },
4740                    children: Vec::new(),
4741                }
4742        )
4743    }
4744    #[test]
4745    fn cylinder_from_nheight_radius1_radius2_center_fn() {
4746        let cylinder = cylinder!(h=12.0, r1=2.0, r2=1.0, center=true, fn=12);
4747        assert!(
4748            cylinder
4749                == Scad {
4750                    op: ScadOp::Cylinder {
4751                        height: 12.0,
4752                        radius1: 2.0,
4753                        radius2: 1.0,
4754                        center: true,
4755                        fa: None,
4756                        fs: None,
4757                        fn_: Some(12),
4758                    },
4759                    children: Vec::new(),
4760                }
4761        )
4762    }
4763
4764    #[test]
4765    fn cylinder_from_nheight_diameter() {
4766        let cylinder = cylinder!(h = 12.0, d = 2.0);
4767        assert!(
4768            cylinder
4769                == Scad {
4770                    op: ScadOp::Cylinder {
4771                        height: 12.0,
4772                        radius1: 1.0,
4773                        radius2: 1.0,
4774                        center: false,
4775                        fa: None,
4776                        fs: None,
4777                        fn_: None,
4778                    },
4779                    children: Vec::new(),
4780                }
4781        )
4782    }
4783
4784    #[test]
4785    fn cylinder_from_nheight_diameter1_diameter2() {
4786        let cylinder = cylinder!(h = 12.0, d1 = 4.0, d2 = 2.0);
4787        assert!(
4788            cylinder
4789                == Scad {
4790                    op: ScadOp::Cylinder {
4791                        height: 12.0,
4792                        radius1: 2.0,
4793                        radius2: 1.0,
4794                        center: false,
4795                        fa: None,
4796                        fs: None,
4797                        fn_: None,
4798                    },
4799                    children: Vec::new(),
4800                }
4801        )
4802    }
4803
4804    #[test]
4805    fn cylinder_from_nheight_diameter1_diameter2_center() {
4806        let cylinder = cylinder!(h = 12.0, d1 = 2.0, d2 = 1.0, center = true);
4807        assert!(
4808            cylinder
4809                == Scad {
4810                    op: ScadOp::Cylinder {
4811                        height: 12.0,
4812                        radius1: 1.0,
4813                        radius2: 0.5,
4814                        center: true,
4815                        fa: None,
4816                        fs: None,
4817                        fn_: None,
4818                    },
4819                    children: Vec::new(),
4820                }
4821        )
4822    }
4823    #[test]
4824    fn cylinder_from_nheight_diameter1_diameter2_center_fa() {
4825        let cylinder = cylinder!(h = 12.0, d1 = 4.0, d2 = 2.0, center = true, fa = 4.0);
4826        assert!(
4827            cylinder
4828                == Scad {
4829                    op: ScadOp::Cylinder {
4830                        height: 12.0,
4831                        radius1: 2.0,
4832                        radius2: 1.0,
4833                        center: true,
4834                        fa: Some(4.0),
4835                        fs: None,
4836                        fn_: None,
4837                    },
4838                    children: Vec::new(),
4839                }
4840        )
4841    }
4842    #[test]
4843    fn cylinder_from_nheight_diameter1_diameter2_center_fs() {
4844        let cylinder = cylinder!(h = 12.0, d1 = 4.0, d2 = 2.0, center = true, fs = 0.25);
4845        assert!(
4846            cylinder
4847                == Scad {
4848                    op: ScadOp::Cylinder {
4849                        height: 12.0,
4850                        radius1: 2.0,
4851                        radius2: 1.0,
4852                        center: true,
4853                        fa: None,
4854                        fs: Some(0.25),
4855                        fn_: None,
4856                    },
4857                    children: Vec::new(),
4858                }
4859        )
4860    }
4861    #[test]
4862    fn cylinder_from_nheight_diameter1_diameter2_center_fa_fs() {
4863        let cylinder = cylinder!(
4864            h = 12.0,
4865            d1 = 2.0,
4866            d2 = 1.0,
4867            center = true,
4868            fa = 2.0,
4869            fs = 0.1
4870        );
4871        assert!(
4872            cylinder
4873                == Scad {
4874                    op: ScadOp::Cylinder {
4875                        height: 12.0,
4876                        radius1: 1.0,
4877                        radius2: 0.5,
4878                        center: true,
4879                        fa: Some(2.0),
4880                        fs: Some(0.1),
4881                        fn_: None,
4882                    },
4883                    children: Vec::new(),
4884                }
4885        )
4886    }
4887    #[test]
4888    fn cylinder_from_nheight_diameter1_diameter2_center_fn() {
4889        let cylinder = cylinder!(h=12.0, d1=2.0, d2=1.0, center=true, fn=12);
4890        assert!(
4891            cylinder
4892                == Scad {
4893                    op: ScadOp::Cylinder {
4894                        height: 12.0,
4895                        radius1: 1.0,
4896                        radius2: 0.5,
4897                        center: true,
4898                        fa: None,
4899                        fs: None,
4900                        fn_: Some(12),
4901                    },
4902                    children: Vec::new(),
4903                }
4904        )
4905    }
4906
4907    #[test]
4908    fn polyhedron_from_points_faces() {
4909        let points = Pt3s::from_pt3s(vec![
4910            Pt3::new(0.0, 0.0, 0.0),
4911            Pt3::new(10.0, 0.0, 0.0),
4912            Pt3::new(10.0, 7.0, 0.0),
4913            Pt3::new(0.0, 7.0, 0.0),
4914            Pt3::new(0.0, 0.0, 5.0),
4915            Pt3::new(10.0, 0.0, 5.0),
4916            Pt3::new(10.0, 7.0, 5.0),
4917            Pt3::new(0.0, 7.0, 5.0),
4918        ]);
4919        let faces = Faces::from_faces(vec![
4920            Indices::from_indices(vec![0, 1, 2, 3]),
4921            Indices::from_indices(vec![4, 5, 1, 0]),
4922            Indices::from_indices(vec![7, 6, 5, 4]),
4923            Indices::from_indices(vec![5, 6, 2, 1]),
4924            Indices::from_indices(vec![6, 7, 3, 2]),
4925            Indices::from_indices(vec![7, 4, 0, 3]),
4926        ]);
4927        let polyhedron = polyhedron!(points.clone(), faces.clone());
4928        assert!(
4929            polyhedron
4930                == Scad {
4931                    op: ScadOp::Polyhedron {
4932                        points,
4933                        faces,
4934                        convexity: 1
4935                    },
4936                    children: Vec::new(),
4937                }
4938        )
4939    }
4940
4941    #[test]
4942    fn polyhedron_from_points_faces_convexity() {
4943        let points = Pt3s::from_pt3s(vec![
4944            Pt3::new(0.0, 0.0, 0.0),
4945            Pt3::new(10.0, 0.0, 0.0),
4946            Pt3::new(10.0, 7.0, 0.0),
4947            Pt3::new(0.0, 7.0, 0.0),
4948            Pt3::new(0.0, 0.0, 5.0),
4949            Pt3::new(10.0, 0.0, 5.0),
4950            Pt3::new(10.0, 7.0, 5.0),
4951            Pt3::new(0.0, 7.0, 5.0),
4952        ]);
4953        let faces = Faces::from_faces(vec![
4954            Indices::from_indices(vec![0, 1, 2, 3]),
4955            Indices::from_indices(vec![4, 5, 1, 0]),
4956            Indices::from_indices(vec![7, 6, 5, 4]),
4957            Indices::from_indices(vec![5, 6, 2, 1]),
4958            Indices::from_indices(vec![6, 7, 3, 2]),
4959            Indices::from_indices(vec![7, 4, 0, 3]),
4960        ]);
4961        let polyhedron = polyhedron!(points.clone(), faces.clone(), 4);
4962        assert!(
4963            polyhedron
4964                == Scad {
4965                    op: ScadOp::Polyhedron {
4966                        points,
4967                        faces,
4968                        convexity: 4
4969                    },
4970                    children: Vec::new(),
4971                }
4972        )
4973    }
4974
4975    #[test]
4976    fn polyhedron_from_npoints_faces_convexity() {
4977        let points = Pt3s::from_pt3s(vec![
4978            Pt3::new(0.0, 0.0, 0.0),
4979            Pt3::new(10.0, 0.0, 0.0),
4980            Pt3::new(10.0, 7.0, 0.0),
4981            Pt3::new(0.0, 7.0, 0.0),
4982            Pt3::new(0.0, 0.0, 5.0),
4983            Pt3::new(10.0, 0.0, 5.0),
4984            Pt3::new(10.0, 7.0, 5.0),
4985            Pt3::new(0.0, 7.0, 5.0),
4986        ]);
4987        let faces = Faces::from_faces(vec![
4988            Indices::from_indices(vec![0, 1, 2, 3]),
4989            Indices::from_indices(vec![4, 5, 1, 0]),
4990            Indices::from_indices(vec![7, 6, 5, 4]),
4991            Indices::from_indices(vec![5, 6, 2, 1]),
4992            Indices::from_indices(vec![6, 7, 3, 2]),
4993            Indices::from_indices(vec![7, 4, 0, 3]),
4994        ]);
4995        let polyhedron = polyhedron!(
4996            points = points.clone(),
4997            faces = faces.clone(),
4998            convexity = 4
4999        );
5000        assert!(
5001            polyhedron
5002                == Scad {
5003                    op: ScadOp::Polyhedron {
5004                        points,
5005                        faces,
5006                        convexity: 4
5007                    },
5008                    children: Vec::new(),
5009                }
5010        )
5011    }
5012
5013    #[test]
5014    fn linear_extrude_from_height_children() {
5015        let child = cube!([10.0, 3.0, 7.5]);
5016        let linear_extrude = linear_extrude!(10.0,
5017            cube!([10.0, 3.0, 7.5]);
5018        );
5019        assert!(
5020            linear_extrude
5021                == Scad {
5022                    op: ScadOp::LinearExtrude {
5023                        height: 10.0,
5024                        center: false,
5025                        convexity: 1,
5026                        twist: 0.0,
5027                        scale: Pt2::new(1.0, 1.0),
5028                        slices: None,
5029                        fn_: None,
5030                    },
5031                    children: vec![child],
5032                }
5033        )
5034    }
5035
5036    #[test]
5037    fn linear_extrude_from_all_slices_children() {
5038        let child = cube!([10.0, 3.0, 7.5]);
5039        let linear_extrude = linear_extrude!(height=10.0, center=false, convexity=1, twist=0.0, scale=1.0, slices=10,
5040            cube!([10.0, 3.0, 7.5]);
5041        );
5042        assert!(
5043            linear_extrude
5044                == Scad {
5045                    op: ScadOp::LinearExtrude {
5046                        height: 10.0,
5047                        center: false,
5048                        convexity: 1,
5049                        twist: 0.0,
5050                        scale: Pt2::new(1.0, 1.0),
5051                        slices: Some(10),
5052                        fn_: None,
5053                    },
5054                    children: vec![child],
5055                }
5056        )
5057    }
5058
5059    #[test]
5060    fn linear_extrude_from_all_fn_children() {
5061        let child = cube!([10.0, 3.0, 7.5]);
5062        let linear_extrude = linear_extrude!(height=10.0, center=false, convexity=1, twist=0.0, scale=1.0, fn=10,
5063            cube!([10.0, 3.0, 7.5]);
5064        );
5065        assert!(
5066            linear_extrude
5067                == Scad {
5068                    op: ScadOp::LinearExtrude {
5069                        height: 10.0,
5070                        center: false,
5071                        convexity: 1,
5072                        twist: 0.0,
5073                        scale: Pt2::new(1.0, 1.0),
5074                        slices: None,
5075                        fn_: Some(10),
5076                    },
5077                    children: vec![child],
5078                }
5079        )
5080    }
5081
5082    #[test]
5083    fn linear_extrude_from_all_separate_scale_slices_children() {
5084        let child = cube!([10.0, 3.0, 7.5]);
5085        let linear_extrude = linear_extrude!(height=10.0, center=false, convexity=1, twist=0.0, scale=[2.0, 1.0], slices=10,
5086            cube!([10.0, 3.0, 7.5]);
5087        );
5088        assert!(
5089            linear_extrude
5090                == Scad {
5091                    op: ScadOp::LinearExtrude {
5092                        height: 10.0,
5093                        center: false,
5094                        convexity: 1,
5095                        twist: 0.0,
5096                        scale: Pt2::new(2.0, 1.0),
5097                        slices: Some(10),
5098                        fn_: None,
5099                    },
5100                    children: vec![child],
5101                }
5102        )
5103    }
5104
5105    #[test]
5106    fn linear_extrude_from_all_separate_scale_fn_children() {
5107        let child = cube!([10.0, 3.0, 7.5]);
5108        let linear_extrude = linear_extrude!(height=10.0, center=false, convexity=1, twist=0.0, scale=[1.0, 2.0], fn=10,
5109            cube!([10.0, 3.0, 7.5]);
5110        );
5111        assert!(
5112            linear_extrude
5113                == Scad {
5114                    op: ScadOp::LinearExtrude {
5115                        height: 10.0,
5116                        center: false,
5117                        convexity: 1,
5118                        twist: 0.0,
5119                        scale: Pt2::new(1.0, 2.0),
5120                        slices: None,
5121                        fn_: Some(10),
5122                    },
5123                    children: vec![child],
5124                }
5125        )
5126    }
5127
5128    #[test]
5129    fn rotate_extrude_from_children() {
5130        let rotate_extrude = rotate_extrude!(square!(1.0););
5131        assert!(
5132            rotate_extrude
5133                == Scad {
5134                    op: ScadOp::RotateExtrude {
5135                        angle: 360.0,
5136                        convexity: 1,
5137                        fa: None,
5138                        fs: None,
5139                        fn_: None,
5140                    },
5141                    children: vec![square!(1.0)],
5142                }
5143        )
5144    }
5145
5146    #[test]
5147    fn rotate_extrude_from_angle() {
5148        let rotate_extrude = rotate_extrude!(angle=45.0, square!(1.0););
5149        assert!(
5150            rotate_extrude
5151                == Scad {
5152                    op: ScadOp::RotateExtrude {
5153                        angle: 45.0,
5154                        convexity: 1,
5155                        fa: None,
5156                        fs: None,
5157                        fn_: None,
5158                    },
5159                    children: vec![square!(1.0)],
5160                }
5161        )
5162    }
5163
5164    #[test]
5165    fn rotate_extrude_from_angle_convexity() {
5166        let rotate_extrude = rotate_extrude!(angle=45.0, convexity=12, square!(1.0););
5167        assert!(
5168            rotate_extrude
5169                == Scad {
5170                    op: ScadOp::RotateExtrude {
5171                        angle: 45.0,
5172                        convexity: 12,
5173                        fa: None,
5174                        fs: None,
5175                        fn_: None,
5176                    },
5177                    children: vec![square!(1.0)],
5178                }
5179        )
5180    }
5181
5182    #[test]
5183    fn rotate_extrude_from_angle_convexity_fa() {
5184        let rotate_extrude = rotate_extrude!(angle=45.0, convexity=12, fa=2.0, square!(1.0););
5185        assert!(
5186            rotate_extrude
5187                == Scad {
5188                    op: ScadOp::RotateExtrude {
5189                        angle: 45.0,
5190                        convexity: 12,
5191                        fa: Some(2.0),
5192                        fs: None,
5193                        fn_: None,
5194                    },
5195                    children: vec![square!(1.0)],
5196                }
5197        )
5198    }
5199
5200    #[test]
5201    fn rotate_extrude_from_angle_convexity_fs() {
5202        let rotate_extrude = rotate_extrude!(angle=45.0, convexity=12, fs=2.0, square!(1.0););
5203        assert!(
5204            rotate_extrude
5205                == Scad {
5206                    op: ScadOp::RotateExtrude {
5207                        angle: 45.0,
5208                        convexity: 12,
5209                        fa: None,
5210                        fs: Some(2.0),
5211                        fn_: None,
5212                    },
5213                    children: vec![square!(1.0)],
5214                }
5215        )
5216    }
5217
5218    #[test]
5219    fn rotate_extrude_from_angle_convexity_fa_fs() {
5220        let rotate_extrude =
5221            rotate_extrude!(angle=45.0, convexity=12, fa=1.5, fs=2.0, square!(1.0););
5222        assert!(
5223            rotate_extrude
5224                == Scad {
5225                    op: ScadOp::RotateExtrude {
5226                        angle: 45.0,
5227                        convexity: 12,
5228                        fa: Some(1.5),
5229                        fs: Some(2.0),
5230                        fn_: None,
5231                    },
5232                    children: vec![square!(1.0)],
5233                }
5234        )
5235    }
5236
5237    #[test]
5238    fn rotate_extrude_from_angle_convexity_fn() {
5239        let rotate_extrude = rotate_extrude!(angle=45.0, convexity=12, fn=6, square!(1.0););
5240        assert!(
5241            rotate_extrude
5242                == Scad {
5243                    op: ScadOp::RotateExtrude {
5244                        angle: 45.0,
5245                        convexity: 12,
5246                        fa: None,
5247                        fs: None,
5248                        fn_: Some(6),
5249                    },
5250                    children: vec![square!(1.0)],
5251                }
5252        )
5253    }
5254
5255    #[test]
5256    fn surface_from_file() {
5257        let surface = surface!("test.data");
5258        assert!(
5259            surface
5260                == Scad {
5261                    op: ScadOp::Surface {
5262                        file: "test.data".to_string(),
5263                        center: false,
5264                        invert: false,
5265                        convexity: 1,
5266                    },
5267                    children: Vec::new(),
5268                }
5269        )
5270    }
5271
5272    #[test]
5273    fn surface_from_all() {
5274        let surface = surface!(
5275            file = "test.data",
5276            center = true,
5277            invert = true,
5278            convexity = 12
5279        );
5280        assert!(
5281            surface
5282                == Scad {
5283                    op: ScadOp::Surface {
5284                        file: "test.data".to_string(),
5285                        center: true,
5286                        invert: true,
5287                        convexity: 12,
5288                    },
5289                    children: Vec::new(),
5290                }
5291        )
5292    }
5293
5294    #[test]
5295    fn translate_from_point_children() {
5296        let translate = translate!([1.0, 2.0, 3.0],
5297            circle!(10.0);
5298        );
5299        assert!(
5300            translate
5301                == Scad {
5302                    op: ScadOp::Translate {
5303                        v: Pt3::new(1.0, 2.0, 3.0)
5304                    },
5305                    children: vec![circle!(10.0)],
5306                }
5307        )
5308    }
5309
5310    #[test]
5311    fn translate_from_npoint_children() {
5312        let translate = translate!(v=[1.0, 2.0, 3.0],
5313            circle!(10.0);
5314        );
5315        assert!(
5316            translate
5317                == Scad {
5318                    op: ScadOp::Translate {
5319                        v: Pt3::new(1.0, 2.0, 3.0)
5320                    },
5321                    children: vec![circle!(10.0)],
5322                }
5323        )
5324    }
5325
5326    #[test]
5327    fn rotate_from_point_children() {
5328        let rotate = rotate!([0.0, 180.0, 0.0], square!(1.0););
5329        assert!(
5330            rotate
5331                == Scad {
5332                    op: ScadOp::Rotate {
5333                        a: None,
5334                        a_is_scalar: false,
5335                        v: Pt3::new(0.0, 180.0, 0.0),
5336                    },
5337                    children: vec![square!(1.0)]
5338                }
5339        )
5340    }
5341
5342    #[test]
5343    fn rotate_from_npoint_children() {
5344        let rotate = rotate!(a=[0.0, 180.0, 0.0], square!(1.0););
5345        assert!(
5346            rotate
5347                == Scad {
5348                    op: ScadOp::Rotate {
5349                        a: None,
5350                        a_is_scalar: false,
5351                        v: Pt3::new(0.0, 180.0, 0.0),
5352                    },
5353                    children: vec![square!(1.0)]
5354                }
5355        )
5356    }
5357
5358    #[test]
5359    fn rotate_from_scalar_children() {
5360        let rotate = rotate!(180.0, square!(1.0););
5361        assert!(
5362            rotate
5363                == Scad {
5364                    op: ScadOp::Rotate {
5365                        a: Some(180.0),
5366                        a_is_scalar: true,
5367                        v: Pt3::new(0.0, 0.0, 0.0),
5368                    },
5369                    children: vec![square!(1.0)]
5370                }
5371        )
5372    }
5373
5374    #[test]
5375    fn rotate_from_nscalar_children() {
5376        let rotate = rotate!(a=180.0, square!(1.0););
5377        assert!(
5378            rotate
5379                == Scad {
5380                    op: ScadOp::Rotate {
5381                        a: Some(180.0),
5382                        a_is_scalar: true,
5383                        v: Pt3::new(0.0, 0.0, 0.0),
5384                    },
5385                    children: vec![square!(1.0)]
5386                }
5387        )
5388    }
5389
5390    #[test]
5391    fn rotate_from_angle_axis_children() {
5392        let rotate = rotate!(180.0, [0.0, 1.0, 0.0], square!(1.0););
5393        assert!(
5394            rotate
5395                == Scad {
5396                    op: ScadOp::Rotate {
5397                        a: Some(180.0),
5398                        a_is_scalar: false,
5399                        v: Pt3::new(0.0, 1.0, 0.0),
5400                    },
5401                    children: vec![square!(1.0)]
5402                }
5403        )
5404    }
5405
5406    #[test]
5407    fn rotate_from_nangle_axis_children() {
5408        let rotate = rotate!(a=180.0, v=[0.0, 1.0, 0.0], square!(1.0););
5409        assert!(
5410            rotate
5411                == Scad {
5412                    op: ScadOp::Rotate {
5413                        a: Some(180.0),
5414                        a_is_scalar: false,
5415                        v: Pt3::new(0.0, 1.0, 0.0),
5416                    },
5417                    children: vec![square!(1.0)]
5418                }
5419        )
5420    }
5421
5422    #[test]
5423    fn scale_from_vector_children() {
5424        let scale = scale!([2.0, 1.0, 2.0], square!(1.0););
5425        assert!(
5426            scale
5427                == Scad {
5428                    op: ScadOp::Scale {
5429                        v: Pt3::new(2.0, 1.0, 2.0),
5430                    },
5431                    children: vec![square!(1.0)]
5432                }
5433        )
5434    }
5435
5436    #[test]
5437    fn scale_from_nvector_children() {
5438        let scale = scale!(v=[2.0, 1.0, 2.0], square!(1.0););
5439        assert!(
5440            scale
5441                == Scad {
5442                    op: ScadOp::Scale {
5443                        v: Pt3::new(2.0, 1.0, 2.0),
5444                    },
5445                    children: vec![square!(1.0)]
5446                }
5447        )
5448    }
5449
5450    #[test]
5451    fn resize_from_size_children() {
5452        let resize = resize!([2.0, 2.0, 6.0], cube!(10.0););
5453        assert!(
5454            resize
5455                == Scad {
5456                    op: ScadOp::Resize {
5457                        newsize: Pt3::new(2.0, 2.0, 6.0),
5458                        auto: false,
5459                        auto_is_vec: false,
5460                        autovec: (false, false, false),
5461                        convexity: 1,
5462                    },
5463                    children: vec![cube!(10.0)],
5464                }
5465        )
5466    }
5467
5468    #[test]
5469    fn resize_from_size_auto_children() {
5470        let resize = resize!([2.0, 2.0, 6.0], true, cube!(10.0););
5471        assert!(
5472            resize
5473                == Scad {
5474                    op: ScadOp::Resize {
5475                        newsize: Pt3::new(2.0, 2.0, 6.0),
5476                        auto: true,
5477                        auto_is_vec: false,
5478                        autovec: (false, false, false),
5479                        convexity: 1,
5480                    },
5481                    children: vec![cube!(10.0)],
5482                }
5483        )
5484    }
5485
5486    #[test]
5487    fn resize_from_size_autovec_children() {
5488        let resize = resize!([2.0, 2.0, 6.0], [true, false, true], cube!(10.0););
5489        assert!(
5490            resize
5491                == Scad {
5492                    op: ScadOp::Resize {
5493                        newsize: Pt3::new(2.0, 2.0, 6.0),
5494                        auto: false,
5495                        auto_is_vec: true,
5496                        autovec: (true, false, true),
5497                        convexity: 1,
5498                    },
5499                    children: vec![cube!(10.0)],
5500                }
5501        )
5502    }
5503
5504    #[test]
5505    fn resize_from_size_auto_convexity_children() {
5506        let resize = resize!([2.0, 2.0, 6.0], true, 10, cube!(10.0););
5507        assert!(
5508            resize
5509                == Scad {
5510                    op: ScadOp::Resize {
5511                        newsize: Pt3::new(2.0, 2.0, 6.0),
5512                        auto: true,
5513                        auto_is_vec: false,
5514                        autovec: (false, false, false),
5515                        convexity: 10,
5516                    },
5517                    children: vec![cube!(10.0)],
5518                }
5519        )
5520    }
5521
5522    #[test]
5523    fn resize_from_size_autovec_convexity_children() {
5524        let resize = resize!([2.0, 2.0, 6.0], [true, false, true], 10, cube!(10.0););
5525        assert!(
5526            resize
5527                == Scad {
5528                    op: ScadOp::Resize {
5529                        newsize: Pt3::new(2.0, 2.0, 6.0),
5530                        auto: false,
5531                        auto_is_vec: true,
5532                        autovec: (true, false, true),
5533                        convexity: 10,
5534                    },
5535                    children: vec![cube!(10.0)],
5536                }
5537        )
5538    }
5539
5540    #[test]
5541    fn resize_from_nsize_children() {
5542        let resize = resize!(newsize=[2.0, 2.0, 6.0], cube!(10.0););
5543        assert!(
5544            resize
5545                == Scad {
5546                    op: ScadOp::Resize {
5547                        newsize: Pt3::new(2.0, 2.0, 6.0),
5548                        auto: false,
5549                        auto_is_vec: false,
5550                        autovec: (false, false, false),
5551                        convexity: 1,
5552                    },
5553                    children: vec![cube!(10.0)],
5554                }
5555        )
5556    }
5557
5558    #[test]
5559    fn resize_from_nsize_auto_children() {
5560        let resize = resize!(newsize=[2.0, 2.0, 6.0], auto=true, cube!(10.0););
5561        assert!(
5562            resize
5563                == Scad {
5564                    op: ScadOp::Resize {
5565                        newsize: Pt3::new(2.0, 2.0, 6.0),
5566                        auto: true,
5567                        auto_is_vec: false,
5568                        autovec: (false, false, false),
5569                        convexity: 1,
5570                    },
5571                    children: vec![cube!(10.0)],
5572                }
5573        )
5574    }
5575
5576    #[test]
5577    fn resize_from_nsize_autovec_children() {
5578        let resize = resize!(newsize=[2.0, 2.0, 6.0], auto=[true, false, true], cube!(10.0););
5579        assert!(
5580            resize
5581                == Scad {
5582                    op: ScadOp::Resize {
5583                        newsize: Pt3::new(2.0, 2.0, 6.0),
5584                        auto: false,
5585                        auto_is_vec: true,
5586                        autovec: (true, false, true),
5587                        convexity: 1,
5588                    },
5589                    children: vec![cube!(10.0)],
5590                }
5591        )
5592    }
5593
5594    #[test]
5595    fn resize_from_nsize_auto_convexity_children() {
5596        let resize = resize!(newsize=[2.0, 2.0, 6.0], auto=true, convexity=10, cube!(10.0););
5597        assert!(
5598            resize
5599                == Scad {
5600                    op: ScadOp::Resize {
5601                        newsize: Pt3::new(2.0, 2.0, 6.0),
5602                        auto: true,
5603                        auto_is_vec: false,
5604                        autovec: (false, false, false),
5605                        convexity: 10,
5606                    },
5607                    children: vec![cube!(10.0)],
5608                }
5609        )
5610    }
5611
5612    #[test]
5613    fn resize_from_nsize_autovec_convexity_children() {
5614        let resize =
5615            resize!(newsize=[2.0, 2.0, 6.0], auto=[true, false, true], convexity=10, cube!(10.0););
5616        assert!(
5617            resize
5618                == Scad {
5619                    op: ScadOp::Resize {
5620                        newsize: Pt3::new(2.0, 2.0, 6.0),
5621                        auto: false,
5622                        auto_is_vec: true,
5623                        autovec: (true, false, true),
5624                        convexity: 10,
5625                    },
5626                    children: vec![cube!(10.0)],
5627                }
5628        )
5629    }
5630
5631    #[test]
5632    fn mirror_from_vec_children() {
5633        let mirror = mirror!([1.0, 1.0, 1.0], cube!(20.0););
5634        assert!(
5635            mirror
5636                == Scad {
5637                    op: ScadOp::Mirror {
5638                        v: Pt3::new(1.0, 1.0, 1.0)
5639                    },
5640                    children: vec![cube!(20.0)],
5641                }
5642        )
5643    }
5644
5645    #[test]
5646    fn mirror_from_nvec_children() {
5647        let mirror = mirror!(v=[1.0, 1.0, 1.0], cube!(20.0););
5648        assert!(
5649            mirror
5650                == Scad {
5651                    op: ScadOp::Mirror {
5652                        v: Pt3::new(1.0, 1.0, 1.0)
5653                    },
5654                    children: vec![cube!(20.0)],
5655                }
5656        )
5657    }
5658
5659    #[test]
5660    fn color_from_pt4_children() {
5661        let color = color!([0.18, 0.18, 0.18, 1.0], cube!(20.0););
5662        assert!(
5663            color
5664                == Scad {
5665                    op: ScadOp::Color {
5666                        rgba: Some(Pt4::new(0.18, 0.18, 0.18, 1.0)),
5667                        color: None,
5668                        hex: None,
5669                        alpha: None,
5670                    },
5671                    children: vec![cube!(20.0)],
5672                }
5673        )
5674    }
5675
5676    #[test]
5677    fn color_from_hex_children() {
5678        let color = color!("#12345678", cube!(20.0););
5679        assert!(
5680            color
5681                == Scad {
5682                    op: ScadOp::Color {
5683                        rgba: None,
5684                        color: None,
5685                        hex: Some("#12345678".to_string()),
5686                        alpha: None,
5687                    },
5688                    children: vec![cube!(20.0)],
5689                }
5690        )
5691    }
5692
5693    #[test]
5694    fn color_from_color_children() {
5695        let color = color!(c=ScadColor::BlanchedAlmond, cube!(20.0););
5696        assert!(
5697            color
5698                == Scad {
5699                    op: ScadOp::Color {
5700                        rgba: None,
5701                        color: Some(ScadColor::BlanchedAlmond),
5702                        hex: None,
5703                        alpha: None,
5704                    },
5705                    children: vec![cube!(20.0)],
5706                }
5707        )
5708    }
5709
5710    #[test]
5711    fn color_from_color_alpha_children() {
5712        let color = color!(c=ScadColor::BlanchedAlmond, alpha=0.75, cube!(20.0););
5713        assert!(
5714            color
5715                == Scad {
5716                    op: ScadOp::Color {
5717                        rgba: None,
5718                        color: Some(ScadColor::BlanchedAlmond),
5719                        hex: None,
5720                        alpha: Some(0.75),
5721                    },
5722                    children: vec![cube!(20.0)],
5723                }
5724        )
5725    }
5726
5727    #[test]
5728    fn offset_from_r_children() {
5729        let offset = offset!(0.75, square!(20.0););
5730        assert!(
5731            offset
5732                == Scad {
5733                    op: ScadOp::Offset {
5734                        r: Some(0.75),
5735                        delta: None,
5736                        chamfer: false,
5737                    },
5738                    children: vec![square!(20.0)],
5739                }
5740        )
5741    }
5742
5743    #[test]
5744    fn offset_from_delta_chamfer_children() {
5745        let offset = offset!(delta=0.75, chamfer=true, square!(20.0););
5746        assert!(
5747            offset
5748                == Scad {
5749                    op: ScadOp::Offset {
5750                        r: None,
5751                        delta: Some(0.75),
5752                        chamfer: true,
5753                    },
5754                    children: vec![square!(20.0)],
5755                }
5756        )
5757    }
5758
5759    #[test]
5760    fn hull_from_children() {
5761        let hull = hull!(square!(20.0););
5762        assert!(
5763            hull == Scad {
5764                op: ScadOp::Hull,
5765                children: vec![square!(20.0)],
5766            }
5767        )
5768    }
5769
5770    #[test]
5771    fn minkowski_from_children() {
5772        let minkowski = minkowski!(square!(20.0););
5773        assert!(
5774            minkowski
5775                == Scad {
5776                    op: ScadOp::Minkowski { convexity: 1 },
5777                    children: vec![square!(20.0)],
5778                }
5779        )
5780    }
5781
5782    #[test]
5783    fn minkowski_from_convexity_children() {
5784        let minkowski = minkowski!(12, square!(20.0););
5785        assert!(
5786            minkowski
5787                == Scad {
5788                    op: ScadOp::Minkowski { convexity: 12 },
5789                    children: vec![square!(20.0)],
5790                }
5791        )
5792    }
5793}