Moved array and combine objects to new source pattern
reverted align object to only align children have new combine 2 object to preserve old files
This commit is contained in:
parent
57b94fd7a4
commit
564e5e7bf1
11 changed files with 253 additions and 115 deletions
|
|
@ -675,9 +675,9 @@ namespace MatterHackers.MatterControl
|
|||
new SceneSelectionSeparator(),
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
OperationType = typeof(CombineObject3D),
|
||||
OperationType = typeof(CombineObject3D_2),
|
||||
TitleResolver = () => "Combine".Localize(),
|
||||
Action = (sceneContext) => new CombineObject3D().WrapSelectedItemAndSelect(sceneContext.Scene),
|
||||
Action = (sceneContext) => new CombineObject3D_2().WrapSelectedItemAndSelect(sceneContext.Scene),
|
||||
Icon = AggContext.StaticData.LoadIcon("combine.png").SetPreMultiply(),
|
||||
IsEnabled = (scene) =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
{
|
||||
// We need to serialize this so we can remove the arrange and get back to the objects before arranging
|
||||
public List<Aabb> OriginalChildrenBounds = new List<Aabb>();
|
||||
private SelectedChildren _anchorObjectSelector = new SelectedChildren();
|
||||
|
||||
public AlignObject3D()
|
||||
{
|
||||
|
|
@ -154,7 +155,34 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
|
||||
[ShowAsList]
|
||||
[DisplayName("Primary")]
|
||||
public SelectedChildren AnchorObjectSelector { get; set; } = new SelectedChildren();
|
||||
public SelectedChildren AnchorObjectSelector
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Children.Count > 0)
|
||||
{
|
||||
if (_anchorObjectSelector.Count != 1)
|
||||
{
|
||||
_anchorObjectSelector.Clear();
|
||||
_anchorObjectSelector.Add(Children.First().ID);
|
||||
}
|
||||
|
||||
if (!this.Children.Any(c => c.ID == _anchorObjectSelector[0]))
|
||||
{
|
||||
// we don't have an id of any of our current children
|
||||
_anchorObjectSelector.Clear();
|
||||
_anchorObjectSelector.Add(Children.First().ID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_anchorObjectSelector.Clear();
|
||||
}
|
||||
|
||||
return _anchorObjectSelector;
|
||||
}
|
||||
set => _anchorObjectSelector = value;
|
||||
}
|
||||
|
||||
public bool Advanced { get; set; } = false;
|
||||
|
||||
|
|
@ -215,36 +243,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
{
|
||||
get
|
||||
{
|
||||
if (AnchorObjectSelector.Count == 1)
|
||||
{
|
||||
var anchorChild = this.Children.Where(c => c.ID == AnchorObjectSelector[0]).FirstOrDefault();
|
||||
|
||||
if (anchorChild != null)
|
||||
{
|
||||
return anchorChild;
|
||||
}
|
||||
|
||||
// try to update the item if possible
|
||||
var id = AnchorObjectSelector[0];
|
||||
|
||||
// check if we can set it to something better
|
||||
var anchorItem = this.Descendants<IObject3D>().Where(i => i.ID == id).FirstOrDefault();
|
||||
if (anchorItem != null)
|
||||
{
|
||||
// we found the item, try to walk up it to find the last object that has a mesh (probably walking up the mesh wrapper chain)
|
||||
var parentThatIsChildeOfThis = anchorItem.Parents<IObject3D>().Where(i => i.Parent == this).FirstOrDefault();
|
||||
if (parentThatIsChildeOfThis != null)
|
||||
{
|
||||
OriginalChildrenBounds.Clear();
|
||||
AnchorObjectSelector.Clear();
|
||||
AnchorObjectSelector.Add(parentThatIsChildeOfThis.ID);
|
||||
|
||||
return parentThatIsChildeOfThis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return this.Children.Where(c => c.ID == AnchorObjectSelector[0]).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,9 +253,9 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
get
|
||||
{
|
||||
int index = 0;
|
||||
foreach(var child in this.Children)
|
||||
{
|
||||
if(child == AnchorObject)
|
||||
foreach (var child in this.Children)
|
||||
{
|
||||
if (child == AnchorObject)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
|
@ -330,12 +329,6 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
|
||||
using (RebuildLock())
|
||||
{
|
||||
var xxx = this.Parents<MeshWrapperObject3D>().FirstOrDefault();
|
||||
if(xxx != null)
|
||||
{
|
||||
xxx.ResetMeshWrapperMeshes(Object3DPropertyFlags.All, CancellationToken.None);
|
||||
}
|
||||
|
||||
var aabb = this.GetAxisAlignedBoundingBox();
|
||||
|
||||
// TODO: check if the has code for the children
|
||||
|
|
|
|||
|
|
@ -82,10 +82,8 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
|
||||
public override async Task Rebuild()
|
||||
{
|
||||
//let the Operation Source base rebuild first
|
||||
await base.Rebuild();
|
||||
|
||||
var rebuildLock = this.RebuildLock();
|
||||
SourceContainer.Visible = true;
|
||||
|
||||
await ApplicationController.Instance.Tasks.Execute(
|
||||
"Advanced Array".Localize(),
|
||||
|
|
@ -123,6 +121,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
lastChild = next;
|
||||
}
|
||||
});
|
||||
SourceContainer.Visible = false;
|
||||
rebuildLock.Dispose();
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@ of the authors and should not be interpreted as representing official policies,
|
|||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools.EditableTypes;
|
||||
using MatterHackers.VectorMath;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -75,10 +75,8 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
|
||||
public override async Task Rebuild()
|
||||
{
|
||||
//let the Operation Source base rebuild first
|
||||
await base.Rebuild();
|
||||
|
||||
var rebuildLock = this.RebuildLock();
|
||||
SourceContainer.Visible = true;
|
||||
|
||||
await ApplicationController.Instance.Tasks.Execute(
|
||||
"Linear Array".Localize(),
|
||||
|
|
@ -87,24 +85,27 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
|
||||
var sourceContainer = SourceContainer;
|
||||
var newChildren = new List<IObject3D>();
|
||||
|
||||
this.Children.Modify(list =>
|
||||
newChildren.Add(SourceContainer);
|
||||
|
||||
var arrayItem = SourceContainer.Children.First();
|
||||
|
||||
// add in all the array items
|
||||
for (int i = 0; i < Math.Max(Count, 1); i++)
|
||||
{
|
||||
var next = arrayItem.Clone();
|
||||
next.Matrix = arrayItem.Matrix * Matrix4X4.CreateTranslation(Direction.Normal.GetNormal() * Distance * i);
|
||||
newChildren.Add(next);
|
||||
}
|
||||
|
||||
Children.Modify(list =>
|
||||
{
|
||||
list.Clear();
|
||||
// add back in the sourceContainer
|
||||
list.Add(sourceContainer);
|
||||
// get the source item
|
||||
var sourceItem = sourceContainer.Children.First();
|
||||
|
||||
for (int i = 0; i < Math.Max(Count, 1); i++)
|
||||
{
|
||||
var next = sourceItem.Clone();
|
||||
next.Matrix = sourceItem.Matrix * Matrix4X4.CreateTranslation(Direction.Normal.GetNormal() * Distance * i);
|
||||
list.Add(next);
|
||||
}
|
||||
list.AddRange(newChildren);
|
||||
});
|
||||
|
||||
SourceContainer.Visible = false;
|
||||
rebuildLock.Dispose();
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -98,10 +98,8 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
Axis.Origin = this.GetAxisAlignedBoundingBox().Center - new Vector3(-30, 0, 0);
|
||||
}
|
||||
|
||||
//let the Operation Source base rebuild first
|
||||
await base.Rebuild();
|
||||
|
||||
var rebuildLock = this.RebuildLock();
|
||||
SourceContainer.Visible = true;
|
||||
|
||||
await ApplicationController.Instance.Tasks.Execute(
|
||||
"Radial Array".Localize(),
|
||||
|
|
@ -150,6 +148,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
list.Add(next);
|
||||
}
|
||||
});
|
||||
SourceContainer.Visible = false;
|
||||
rebuildLock.Dispose();
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
|
||||
public static IObject3D Plus(this IObject3D a, IObject3D b)
|
||||
{
|
||||
var combine = new CombineObject3D();
|
||||
var combine = new CombineObject3D_2();
|
||||
combine.Children.Add(a.Clone());
|
||||
combine.Children.Add(b.Clone());
|
||||
|
||||
|
|
|
|||
|
|
@ -27,24 +27,18 @@ of the authors and should not be interpreted as representing official policies,
|
|||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.DataConverters3D.UndoCommands;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools.Operations
|
||||
{
|
||||
public class OperationSourceObject3D : Object3D
|
||||
{
|
||||
public OperationSourceObject3D()
|
||||
{
|
||||
Visible = false;
|
||||
Name = "Source".Localize();
|
||||
}
|
||||
}
|
||||
|
||||
public class OperationSourceContainerObject3D : Object3D
|
||||
{
|
||||
[JsonIgnore]
|
||||
|
|
@ -66,12 +60,12 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
{
|
||||
foreach (var child in thisChildren)
|
||||
{
|
||||
thisChildren.Remove(child);
|
||||
sourceChildren.Add(child);
|
||||
}
|
||||
});
|
||||
|
||||
// and then add the source container to this
|
||||
thisChildren.Clear();
|
||||
thisChildren.Add(sourceContainer);
|
||||
});
|
||||
}
|
||||
|
|
@ -112,37 +106,6 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
base.Flatten(undoBuffer);
|
||||
}
|
||||
|
||||
public override async Task Rebuild()
|
||||
{
|
||||
var rebuildLock = this.RebuildLock();
|
||||
|
||||
await ApplicationController.Instance.Tasks.Execute(
|
||||
"Linear Array".Localize(),
|
||||
null,
|
||||
(reporter, cancellationToken) =>
|
||||
{
|
||||
IObject3D sourceContainer = this.Children.FirstOrDefault(c => c is OperationSourceObject3D);
|
||||
if (sourceContainer == null)
|
||||
{
|
||||
sourceContainer = new OperationSourceObject3D();
|
||||
|
||||
// Move first child to sourceContainer
|
||||
var firstChild = this.Children.First();
|
||||
this.Children.Remove(firstChild);
|
||||
sourceContainer.Children.Add(firstChild);
|
||||
}
|
||||
|
||||
this.Children.Modify(list =>
|
||||
{
|
||||
list.Clear();
|
||||
list.Add(sourceContainer);
|
||||
});
|
||||
|
||||
rebuildLock.Dispose();
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
public override void Remove(UndoBuffer undoBuffer)
|
||||
{
|
||||
using (this.RebuildLock())
|
||||
|
|
@ -164,5 +127,62 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
|
||||
base.Remove(undoBuffer);
|
||||
}
|
||||
|
||||
public void RemoveAllButSource()
|
||||
{
|
||||
var sourceContainer = SourceContainer;
|
||||
this.Children.Modify(list =>
|
||||
{
|
||||
list.Clear();
|
||||
list.Add(sourceContainer);
|
||||
});
|
||||
}
|
||||
|
||||
public void WrapSelectedItemAndSelect(InteractiveScene scene)
|
||||
{
|
||||
using (RebuildLock())
|
||||
{
|
||||
var selectedItems = scene.GetSelectedItems();
|
||||
|
||||
if (selectedItems.Count > 0)
|
||||
{
|
||||
// clear the selected item
|
||||
scene.SelectedItem = null;
|
||||
|
||||
using (RebuildLock())
|
||||
{
|
||||
var clonedItemsToAdd = new List<IObject3D>(selectedItems.Select((i) => i.Clone()));
|
||||
|
||||
Children.Modify((list) =>
|
||||
{
|
||||
list.Clear();
|
||||
|
||||
foreach (var child in clonedItemsToAdd)
|
||||
{
|
||||
list.Add(child);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
scene.UndoBuffer.AddAndDo(
|
||||
new ReplaceCommand(
|
||||
new List<IObject3D>(selectedItems),
|
||||
new List<IObject3D> { this }));
|
||||
|
||||
// and select this
|
||||
scene.SelectedItem = this;
|
||||
}
|
||||
}
|
||||
|
||||
Invalidate(new InvalidateArgs(this, InvalidateType.Properties, null));
|
||||
}
|
||||
}
|
||||
|
||||
public class OperationSourceObject3D : Object3D
|
||||
{
|
||||
public OperationSourceObject3D()
|
||||
{
|
||||
Name = "Source".Localize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -172,6 +172,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
Source = item
|
||||
};
|
||||
|
||||
case OperationSourceContainerObject3D operationSourceContainerObject3D:
|
||||
return new ObjectView()
|
||||
{
|
||||
Children = item.Children.OfType<OperationSourceObject3D>().ToList(),
|
||||
Name = operationSourceContainerObject3D.Name,
|
||||
Source = item
|
||||
};
|
||||
|
||||
|
||||
default:
|
||||
return new ObjectView(item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,10 +37,12 @@ using MatterHackers.Agg.UI;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
{
|
||||
[Obsolete("Use CombineObject3D_2 instead", false)]
|
||||
public class CombineObject3D : MeshWrapperObject3D
|
||||
{
|
||||
public CombineObject3D()
|
||||
|
|
@ -65,6 +67,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
await Rebuild();
|
||||
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
|
||||
}
|
||||
|
||||
base.OnInvalidate(invalidateType);
|
||||
}
|
||||
|
||||
public override Task Rebuild()
|
||||
|
|
@ -133,7 +137,120 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
{
|
||||
first.Mesh = result;
|
||||
}
|
||||
item.Visible = false;
|
||||
|
||||
percentCompleted += amountPerOperation;
|
||||
progressStatus.Progress0To1 = percentCompleted;
|
||||
reporter?.Report(progressStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CombineObject3D_2 : OperationSourceContainerObject3D
|
||||
{
|
||||
public CombineObject3D_2()
|
||||
{
|
||||
Name = "Combine";
|
||||
}
|
||||
|
||||
public override async void OnInvalidate(InvalidateArgs invalidateType)
|
||||
{
|
||||
if ((invalidateType.InvalidateType == InvalidateType.Content
|
||||
|| invalidateType.InvalidateType == InvalidateType.Matrix
|
||||
|| invalidateType.InvalidateType == InvalidateType.Mesh)
|
||||
&& invalidateType.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
await Rebuild();
|
||||
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
|
||||
}
|
||||
else if (invalidateType.InvalidateType == InvalidateType.Properties
|
||||
&& invalidateType.Source == this)
|
||||
{
|
||||
await Rebuild();
|
||||
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
|
||||
}
|
||||
|
||||
base.OnInvalidate(invalidateType);
|
||||
}
|
||||
|
||||
public override Task Rebuild()
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
|
||||
var rebuildLocks = this.RebuilLockAll();
|
||||
|
||||
// spin up a task to remove holes from the objects in the group
|
||||
return ApplicationController.Instance.Tasks.Execute(
|
||||
"Combine".Localize(),
|
||||
null,
|
||||
(reporter, cancellationToken) =>
|
||||
{
|
||||
var progressStatus = new ProgressStatus();
|
||||
reporter.Report(progressStatus);
|
||||
|
||||
try
|
||||
{
|
||||
Combine(cancellationToken, reporter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
rebuildLocks.Dispose();
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
public void Combine()
|
||||
{
|
||||
Combine(CancellationToken.None, null);
|
||||
}
|
||||
|
||||
public void Combine(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
|
||||
{
|
||||
SourceContainer.Visible = true;
|
||||
RemoveAllButSource();
|
||||
|
||||
var participants = SourceContainer.VisibleMeshes();
|
||||
if (participants.Count() < 2)
|
||||
{
|
||||
if(participants.Count() == 1)
|
||||
{
|
||||
var newMesh = new Object3D();
|
||||
newMesh.CopyProperties(participants.First(), Object3DPropertyFlags.All);
|
||||
this.Children.Add(newMesh);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var first = participants.First();
|
||||
|
||||
var totalOperations = participants.Count() - 1;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double percentCompleted = 0;
|
||||
|
||||
ProgressStatus progressStatus = new ProgressStatus();
|
||||
foreach (var item in participants)
|
||||
{
|
||||
if (item != first)
|
||||
{
|
||||
var resultMesh = BooleanProcessing.Do(item.Mesh, item.WorldMatrix(),
|
||||
first.Mesh, first.WorldMatrix(),
|
||||
0,
|
||||
reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken);
|
||||
|
||||
var inverse = first.WorldMatrix();
|
||||
inverse.Invert();
|
||||
resultMesh.Transform(inverse);
|
||||
var resultsItem = new Object3D()
|
||||
{
|
||||
Mesh = resultMesh
|
||||
};
|
||||
resultsItem.CopyProperties(first, Object3DPropertyFlags.All);
|
||||
this.Children.Add(resultsItem);
|
||||
|
||||
SourceContainer.Visible = false;
|
||||
|
||||
percentCompleted += amountPerOperation;
|
||||
progressStatus.Progress0To1 = percentCompleted;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit e71579066f1806eab705145f894e99bdedfa6653
|
||||
Subproject commit 51e401c161849a721854774c9e081b6db1edb972
|
||||
|
|
@ -67,7 +67,7 @@ namespace MatterControl.Tests.MatterControl
|
|||
0, -10, -10,
|
||||
20, 10, 10), .001));
|
||||
|
||||
var union = new CombineObject3D();
|
||||
var union = new CombineObject3D_2();
|
||||
union.Children.Add(cubeA);
|
||||
union.Children.Add(offsetCubeB);
|
||||
root.Children.Add(union);
|
||||
|
|
@ -92,7 +92,7 @@ namespace MatterControl.Tests.MatterControl
|
|||
var cubeA = new CubeObject3D(20, 20, 20);
|
||||
var cubeB = new CubeObject3D(20, 20, 20);
|
||||
|
||||
var union = new CombineObject3D();
|
||||
var union = new CombineObject3D_2();
|
||||
union.Children.Add(cubeA);
|
||||
union.Children.Add(cubeB);
|
||||
root.Children.Add(union);
|
||||
|
|
@ -122,7 +122,7 @@ namespace MatterControl.Tests.MatterControl
|
|||
var cubeB = new CubeObject3D(20, 20, 20);
|
||||
var offsetCubeB = new TranslateObject3D(cubeB, 10);
|
||||
|
||||
var combine = new CombineObject3D();
|
||||
var combine = new CombineObject3D_2();
|
||||
combine.Children.Add(cubeA);
|
||||
combine.Children.Add(offsetCubeB);
|
||||
root.Children.Add(combine);
|
||||
|
|
@ -161,7 +161,7 @@ namespace MatterControl.Tests.MatterControl
|
|||
Name = "cubeB"
|
||||
};
|
||||
|
||||
var combine = new CombineObject3D();
|
||||
var combine = new CombineObject3D_2();
|
||||
combine.Children.Add(cubeA);
|
||||
combine.Children.Add(cubeB);
|
||||
root.Children.Add(combine);
|
||||
|
|
@ -194,7 +194,7 @@ namespace MatterControl.Tests.MatterControl
|
|||
var cubeB = new CubeObject3D(20, 20, 20);
|
||||
var offsetCubeB = new TranslateObject3D(cubeB, 10);
|
||||
|
||||
var combine = new CombineObject3D();
|
||||
var combine = new CombineObject3D_2();
|
||||
combine.Children.Add(cubeA);
|
||||
combine.Children.Add(offsetCubeB);
|
||||
root.Children.Add(combine);
|
||||
|
|
@ -247,7 +247,7 @@ namespace MatterControl.Tests.MatterControl
|
|||
group.Children.Add(cubeA);
|
||||
group.Children.Add(offsetCubeB);
|
||||
|
||||
var union = new CombineObject3D();
|
||||
var union = new CombineObject3D_2();
|
||||
union.Children.Add(group);
|
||||
|
||||
root.Children.Add(union);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue