diff --git a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs index 19291b8..c1b74b7 100644 --- a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs +++ b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs @@ -14,8 +14,8 @@ namespace OSCADSharp.ConsoleTests static void Main(string[] args) { - var obj = new Cube(5, 5, 20) - .Translate(30, 0, 0).Rotate(0, 90, 0).Resize(2, 2, 2); + Settings.Globals["$fn"] = 100; + var obj = new Sphere(30); var pos = obj.Position(); var cyl1 = new Cylinder(1, 100, true).Translate(pos); @@ -23,10 +23,10 @@ namespace OSCADSharp.ConsoleTests var cyl3 = new Cylinder(1, 100, true).Rotate(90, 0, 0).Translate(pos); var axisHelper = cyl1.Union(cyl2, cyl3).Color("Red"); - var topCorner = new Sphere().Translate(obj.Bounds().TopRight); - var botCorner = new Sphere().Translate(obj.Bounds().BottomLeft); + //var topCorner = new Sphere().Translate(obj.Bounds().TopRight); + //var botCorner = new Sphere().Translate(obj.Bounds().BottomLeft); - (obj + topCorner + botCorner + axisHelper).ToFile("test.scad"); + (obj + axisHelper).ToFile("test.scad"); //Console.ReadKey(); } diff --git a/OSCADSharp/OSCADSharp.UnitTests/OSCADObjectTests.cs b/OSCADSharp/OSCADSharp.UnitTests/OSCADObjectTests.cs index e64a2a8..de5cb5f 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/OSCADObjectTests.cs +++ b/OSCADSharp/OSCADSharp.UnitTests/OSCADObjectTests.cs @@ -1,4 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using OSCADSharp.Scripting; using OSCADSharp.Solids; using System; using System.Collections.Concurrent; @@ -135,6 +137,39 @@ namespace OSCADSharp.UnitTests Assert.AreEqual("Text", children[0].Name); Assert.AreEqual("Union", children[1].Name); } + + [TestMethod] + public void OSCADObject_ToFileIncludesOSCADSharpGeneratedHeader() + { + var cube = new Cube(); + string[] output = null; + + var mock = new Mock(); + mock.Setup(_wrtr => _wrtr.WriteAllLines(It.IsAny(), It.IsAny())) + .Callback((path, contents) => { output = contents; }); + Settings.FileWriter = mock.Object; + + cube.ToFile("myFile"); + + Assert.AreEqual(Settings.OSCADSharpHeader, output[0]); + } + + [TestMethod] + public void OSCADObject_ToFileIncludesGlobalVariablesDefinedInSettings() + { + var cube = new Cube(); + string[] output = null; + Settings.Globals["$fn"] = 100; + + var mock = new Mock(); + mock.Setup(_wrtr => _wrtr.WriteAllLines(It.IsAny(), It.IsAny())) + .Callback((path, contents) => { output = contents; }); + Settings.FileWriter = mock.Object; + + cube.ToFile("myFile"); + + Assert.AreEqual("$fn = 100;\r\n", output[1]); + } } } diff --git a/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj b/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj index a1e5ecc..83c374d 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj +++ b/OSCADSharp/OSCADSharp.UnitTests/OSCADSharp.UnitTests.csproj @@ -35,6 +35,10 @@ 4 + + ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll + True + @@ -75,6 +79,9 @@ OSCADSharp + + + diff --git a/OSCADSharp/OSCADSharp.UnitTests/Solids/CylinderTests.cs b/OSCADSharp/OSCADSharp.UnitTests/Solids/CylinderTests.cs index b1acbce..5e441f5 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/Solids/CylinderTests.cs +++ b/OSCADSharp/OSCADSharp.UnitTests/Solids/CylinderTests.cs @@ -57,5 +57,34 @@ namespace OSCADSharp.UnitTests Assert.AreEqual(new Vector3(2.5, 2.5, 10), obj.Bounds().TopRight); Assert.AreEqual(new Vector3(-2.5, -2.5, -10), obj.Bounds().BottomLeft); } + + [TestMethod] + public void Cylinder_ScriptOutputDoesNotContainResolutionValuesIfNotSpecified() + { + var cylinder = new Cylinder(); + + string script = cylinder.ToString(); + + Assert.IsTrue(!script.Contains("$fn")); + Assert.IsTrue(!script.Contains("$fa")); + Assert.IsTrue(!script.Contains("$fs")); + } + + [TestMethod] + public void Cylinder_ScriptOutpuHasResolutionValuesIfSpecified() + { + var cylinder = new Cylinder() + { + Resolution = 40, + MinimumAngle = 5, + MinimumCircumferentialLength = 2 + }; + + string script = cylinder.ToString(); + + Assert.IsTrue(script.Contains("$fn")); + Assert.IsTrue(script.Contains("$fa")); + Assert.IsTrue(script.Contains("$fs")); + } } } diff --git a/OSCADSharp/OSCADSharp.UnitTests/Solids/SphereTests.cs b/OSCADSharp/OSCADSharp.UnitTests/Solids/SphereTests.cs index 2cc55d3..e0c5509 100644 --- a/OSCADSharp/OSCADSharp.UnitTests/Solids/SphereTests.cs +++ b/OSCADSharp/OSCADSharp.UnitTests/Solids/SphereTests.cs @@ -86,5 +86,34 @@ namespace OSCADSharp.UnitTests Assert.AreEqual(new Vector3(15, 15, 15), obj.Bounds().TopRight); Assert.AreEqual(new Vector3(-15, -15, -15), obj.Bounds().BottomLeft); } + + [TestMethod] + public void Sphere_ScriptOutputDoesNotContainResolutionValuesIfNotSpecified() + { + var sphere = new Sphere(); + + string script = sphere.ToString(); + + Assert.IsTrue(!script.Contains("$fn")); + Assert.IsTrue(!script.Contains("$fa")); + Assert.IsTrue(!script.Contains("$fs")); + } + + [TestMethod] + public void Sphere_ScriptOutpuHasResolutionValuesIfSpecified() + { + var sphere = new Sphere() + { + Resolution = 40, + MinimumAngle = 5, + MinimumFragmentSize = 2 + }; + + string script = sphere.ToString(); + + Assert.IsTrue(script.Contains("$fn")); + Assert.IsTrue(script.Contains("$fa")); + Assert.IsTrue(script.Contains("$fs")); + } } } diff --git a/OSCADSharp/OSCADSharp.UnitTests/packages.config b/OSCADSharp/OSCADSharp.UnitTests/packages.config new file mode 100644 index 0000000..f8429b5 --- /dev/null +++ b/OSCADSharp/OSCADSharp.UnitTests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/OSCADSharp/OSCADSharp/OSCADObject.cs b/OSCADSharp/OSCADSharp/OSCADObject.cs index 3a41ad7..3e8b537 100644 --- a/OSCADSharp/OSCADSharp/OSCADObject.cs +++ b/OSCADSharp/OSCADSharp/OSCADObject.cs @@ -262,6 +262,11 @@ namespace OSCADSharp return this.ToString() == other.ToString(); } + /// + /// The parent of this object in its OSCADObject tree + /// + internal OSCADObject Parent { get; set; } + /// /// Internal collection of children for this object /// @@ -323,8 +328,13 @@ namespace OSCADSharp { path += ".scad"; } - - File.WriteAllLines(path, new string[] { this.ToString() }); + + Settings.FileWriter.WriteAllLines(path, new string[] + { + Settings.OSCADSharpHeader, + Settings.Globals.ToString(), + this.ToString() + }); } #endregion diff --git a/OSCADSharp/OSCADSharp/OSCADSharp.csproj b/OSCADSharp/OSCADSharp/OSCADSharp.csproj index 23a88dd..1b7c5b0 100644 --- a/OSCADSharp/OSCADSharp/OSCADSharp.csproj +++ b/OSCADSharp/OSCADSharp/OSCADSharp.csproj @@ -42,7 +42,11 @@ + + + + @@ -67,6 +71,7 @@ + diff --git a/OSCADSharp/OSCADSharp/Scripting/DefaultFileWriter.cs b/OSCADSharp/OSCADSharp/Scripting/DefaultFileWriter.cs new file mode 100644 index 0000000..05ae2e4 --- /dev/null +++ b/OSCADSharp/OSCADSharp/Scripting/DefaultFileWriter.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OSCADSharp.Scripting +{ + internal class DefaultFileWriter : IFileWriter + { + public void WriteAllLines(string path, string[] contents) + { + File.WriteAllLines(path, contents); + } + } +} diff --git a/OSCADSharp/OSCADSharp/Scripting/IFileWriter.cs b/OSCADSharp/OSCADSharp/Scripting/IFileWriter.cs new file mode 100644 index 0000000..afdbb46 --- /dev/null +++ b/OSCADSharp/OSCADSharp/Scripting/IFileWriter.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OSCADSharp.Scripting +{ + /// + /// A class that takes text and writes to file + /// + public interface IFileWriter + { + /// + /// Writes lines of text to a file at the path specified + /// + /// + /// + void WriteAllLines(string path, string[] contents); + } +} diff --git a/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs b/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs index f1a8c7c..8faa9d7 100644 --- a/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs +++ b/OSCADSharp/OSCADSharp/Scripting/MultiBlockStatementObject.cs @@ -20,6 +20,10 @@ namespace OSCADSharp.Scripting { this.outerStatement = outerStatement; this.children = children.ToList(); + foreach (var child in children) + { + child.Parent = this; + } } public override string ToString() diff --git a/OSCADSharp/OSCADSharp/Scripting/StatementBuilder.cs b/OSCADSharp/OSCADSharp/Scripting/StatementBuilder.cs new file mode 100644 index 0000000..30171ad --- /dev/null +++ b/OSCADSharp/OSCADSharp/Scripting/StatementBuilder.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OSCADSharp.Scripting +{ + /// + /// Extends the capabilities of StringBuilder with domain-specific behavior + /// + internal class StatementBuilder + { + private StringBuilder SB { get; set; } = new StringBuilder(); + + /// + /// Special append method for conditionally adding value-pairs + /// + /// The Name of the value-pair + /// The value - if null this method does nothing + /// (optional) Flag indicating whether a comma should be added before the value-pair + public void AppendValuePairIfExists(string name, object value, bool prefixWithComma = false) + { + if (!String.IsNullOrEmpty(value?.ToString())) + { + if (prefixWithComma) + { + SB.Append(", "); + } + + SB.Append(name); + SB.Append(" = "); + SB.Append(value); + } + } + + /// + /// Pass-through for StringBuilder.Append + /// + /// + public void Append(string text) + { + SB.Append(text); + } + + /// + /// Pass-through for StringBuilder.AppendLine + /// + /// + public void AppendLine(string text) + { + SB.AppendLine(text); + } + + /// + /// Gets this builder's full string + /// + /// + public override string ToString() + { + return SB.ToString(); + } + } +} diff --git a/OSCADSharp/OSCADSharp/Scripting/Variables.cs b/OSCADSharp/OSCADSharp/Scripting/Variables.cs new file mode 100644 index 0000000..1a47561 --- /dev/null +++ b/OSCADSharp/OSCADSharp/Scripting/Variables.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OSCADSharp.Scripting +{ + /// + /// A collection of names/values for variables + /// + public sealed class Variables + { + private Dictionary variables = new Dictionary(); + + /// + /// Assigns or gets a variable's value + /// + /// + /// + public object this[string name] // long is a 64-bit integer + { + get + { + if (variables.ContainsKey(name)) + { + return variables[name]; + } + else + { + return null; + } + } + set + { + variables[name] = value; + } + } + + /// + /// This class is intended for use in other externally-exposed classes, + /// as such its constructor is not public. + /// + internal Variables() + { + } + + /// + /// Gets the string representation for all variables + /// + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + foreach (var kvp in this.variables) + { + sb.Append(kvp.Key); + sb.Append(" = "); + sb.Append(kvp.Value); + sb.Append(";"); + sb.Append(Environment.NewLine); + } + + return sb.ToString(); + } + } +} diff --git a/OSCADSharp/OSCADSharp/Settings.cs b/OSCADSharp/OSCADSharp/Settings.cs new file mode 100644 index 0000000..d6b183f --- /dev/null +++ b/OSCADSharp/OSCADSharp/Settings.cs @@ -0,0 +1,32 @@ +using OSCADSharp.Scripting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OSCADSharp +{ + /// + /// Settings for OpenSCAD scripts + /// + public static class Settings + { + /// + /// Code-gen header + /// + public static readonly string OSCADSharpHeader = String.Format("/*Code Generated using OSCADSharp on {0}. {1}{2}For more information, please visit https://github.com/Exolun/OSCADSharp */{3}", + DateTime.Now.ToString(), Environment.NewLine, Environment.NewLine, Environment.NewLine); + + /// + /// Global variables that can be assigned for output at the + /// top of OpenSCAD scripts + /// + public static Variables Globals = new Variables(); + + /// + /// Used to write scripts to file + /// + public static IFileWriter FileWriter = new DefaultFileWriter(); + } +} diff --git a/OSCADSharp/OSCADSharp/Solids/Cylinder.cs b/OSCADSharp/OSCADSharp/Solids/Cylinder.cs index 5fe08b8..a70fc47 100644 --- a/OSCADSharp/OSCADSharp/Solids/Cylinder.cs +++ b/OSCADSharp/OSCADSharp/Solids/Cylinder.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using OSCADSharp.Spatial; +using OSCADSharp.Scripting; namespace OSCADSharp.Solids { @@ -81,19 +82,19 @@ namespace OSCADSharp.Solids /// Minimum angle (in degrees) of each cylinder fragment. /// ($fa in OpenSCAD) /// - public int MinimumAngle { get; set; } = 12; + public int? MinimumAngle { get; set; } /// /// Minimum circumferential length of each fragment. /// ($fs in OpenSCAD) /// - public int MinimumCircumferentialLength { get; set; } = 2; + public int? MinimumCircumferentialLength { get; set; } /// /// Number of fragments in 360 degrees. Values of 3 or more override MinimumAngle and MinimumCircumferentialLength /// ($fn in OpenSCAD) /// - public int Resolution { get; set; } = 0; + public int? Resolution { get; set; } #endregion #region Constructors @@ -125,9 +126,18 @@ namespace OSCADSharp.Solids /// Script for this object public override string ToString() { - return String.Format("cylinder($fn = {0}, $fa = {1}, $fs = {2}, h = {3}, r1 = {4}, r2 = {5}, center = {6}); {7}", - Resolution.ToString(), MinimumAngle.ToString(), MinimumCircumferentialLength.ToString(), - Height.ToString(), Radius1.ToString(), Radius2.ToString(), Center.ToString().ToLower(), Environment.NewLine); + var sb = new StatementBuilder(); + sb.Append("cylinder("); + sb.AppendValuePairIfExists("center", this.Center.ToString().ToLower()); + sb.AppendValuePairIfExists("r1", this.Radius1, true); + sb.AppendValuePairIfExists("r2", this.Radius2, true); + sb.AppendValuePairIfExists("h", this.Height, true); + sb.AppendValuePairIfExists("$fn", this.Resolution, true); + sb.AppendValuePairIfExists("$fa", this.MinimumAngle, true); + sb.AppendValuePairIfExists("$fs", this.MinimumCircumferentialLength, true); + sb.Append(");"); + sb.Append(Environment.NewLine); + return sb.ToString(); } /// diff --git a/OSCADSharp/OSCADSharp/Solids/Sphere.cs b/OSCADSharp/OSCADSharp/Solids/Sphere.cs index 766decb..20d2d56 100644 --- a/OSCADSharp/OSCADSharp/Solids/Sphere.cs +++ b/OSCADSharp/OSCADSharp/Solids/Sphere.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using OSCADSharp.Spatial; +using OSCADSharp.Scripting; namespace OSCADSharp.Solids { @@ -30,19 +31,19 @@ namespace OSCADSharp.Solids /// Minimum angle (in degrees) of each cylinder fragment. /// ($fa in OpenSCAD) /// - public int MinimumAngle { get; set; } = 12; + public int? MinimumAngle { get; set; } /// /// Fragment size in mm /// ($fs in OpenSCAD) /// - public int MinimumFragmentSize { get; set; } = 2; + public int? MinimumFragmentSize { get; set; } /// /// Number of fragments in 360 degrees. Values of 3 or more override MinimumAngle and MinimumCircumferentialLength /// ($fn in OpenSCAD) /// - public int Resolution { get; set; } = 0; + public int? Resolution { get; set; } #endregion #region Constructors @@ -70,9 +71,16 @@ namespace OSCADSharp.Solids /// Script for this object public override string ToString() { - return String.Format("sphere($fn = {0}, $fa = {1}, $fs = {2}, r = {3});{4}", - this.Resolution.ToString(), this.MinimumAngle.ToString(), - this.MinimumFragmentSize.ToString(), this.Radius.ToString(), Environment.NewLine); + StatementBuilder sb = new StatementBuilder(); + sb.Append("sphere("); + sb.AppendValuePairIfExists("r", this.Radius); + sb.AppendValuePairIfExists("$fn", this.Resolution, true); + sb.AppendValuePairIfExists("$fa", this.MinimumAngle, true); + sb.AppendValuePairIfExists("$fs", this.MinimumFragmentSize, true); + sb.Append(");"); + sb.Append(Environment.NewLine); + + return sb.ToString(); } /// diff --git a/OSCADSharp/OSCADSharp/Solids/Text3D.cs b/OSCADSharp/OSCADSharp/Solids/Text3D.cs index 888da34..40045cd 100644 --- a/OSCADSharp/OSCADSharp/Solids/Text3D.cs +++ b/OSCADSharp/OSCADSharp/Solids/Text3D.cs @@ -107,22 +107,22 @@ namespace OSCADSharp.Solids /// Script for this object public override string ToString() { - StringBuilder sb = new StringBuilder(); + StatementBuilder sb = new StatementBuilder(); sb.Append("text("); sb.Append("\""); sb.Append(this.Text); sb.Append("\""); - appendIfValueNotNullOrEmpty("size", this.Size?.ToString(), sb); + sb.AppendValuePairIfExists("size", this.Size?.ToString(), true); // Text is always centered in OSCADSharp to ensure correctness of // position interpolation - appendIfValueNotNullOrEmpty("halign", "\"center\"", sb); - appendIfValueNotNullOrEmpty("valign", "\"center\"", sb); + sb.AppendValuePairIfExists("halign", "\"center\"", true); + sb.AppendValuePairIfExists("valign", "\"center\"", true); - appendIfValueNotNullOrEmpty("font", this.Font, sb); - appendIfValueNotNullOrEmpty("spacing", this.Spacing?.ToString(), sb); - appendIfValueNotNullOrEmpty("direction", this.TextDirection?.ToString(), sb); - appendIfValueNotNullOrEmpty("language", this.Language?.ToString(), sb); + sb.AppendValuePairIfExists("font", this.Font, true); + sb.AppendValuePairIfExists("spacing", this.Spacing?.ToString(), true); + sb.AppendValuePairIfExists("direction", this.TextDirection?.ToString(), true); + sb.AppendValuePairIfExists("language", this.Language?.ToString(), true); sb.Append(");"); sb.Append(Environment.NewLine); @@ -145,6 +145,7 @@ namespace OSCADSharp.Solids /// /// Returns the approximate boundaries of this OpenSCAD object + /// /// public override Bounds Bounds() { diff --git a/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs b/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs index 1d57142..9f02c14 100644 --- a/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/ColoredObject.cs @@ -33,6 +33,7 @@ namespace OSCADSharp.Transforms this.Opacity = opacity; this.children.Add(obj); + obj.Parent = this; } public override string ToString() diff --git a/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs b/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs index 0467bb6..0f6900c 100644 --- a/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/LinearExtrudedObject.cs @@ -35,6 +35,7 @@ namespace OSCADSharp.Transforms this.Height = height; this.children.Add(obj); + obj.Parent = this; } public override OSCADObject Clone() diff --git a/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs b/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs index 68796d2..7cad6ca 100644 --- a/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/MirroredObject.cs @@ -32,6 +32,7 @@ namespace OSCADSharp.Transforms this.Normal = normal; this.children.Add(obj); + obj.Parent = this; } public override string ToString() diff --git a/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs b/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs index 6cb5b03..f8eff1a 100644 --- a/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/ResizedObject.cs @@ -30,6 +30,7 @@ namespace OSCADSharp.Transforms this.Size = size; this.children.Add(obj); + obj.Parent = this; } public override string ToString() diff --git a/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs b/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs index 460123d..616b78f 100644 --- a/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/RotatedObject.cs @@ -30,6 +30,7 @@ namespace OSCADSharp.Transforms this.Angle = angle; this.children.Add(obj); + obj.Parent = this; } public override string ToString() diff --git a/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs b/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs index 5bcee35..e4d230e 100644 --- a/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/ScaledObject.cs @@ -30,6 +30,7 @@ namespace OSCADSharp.Transforms this.ScaleFactor = scale; this.children.Add(obj); + obj.Parent = this; } public override string ToString() diff --git a/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs b/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs index a1cd635..b8445f3 100644 --- a/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs +++ b/OSCADSharp/OSCADSharp/Transforms/TranslatedObject.cs @@ -27,6 +27,7 @@ namespace OSCADSharp.Transforms this.Vector = vector; this.children.Add(obj); + obj.Parent = this; } public override string ToString()