public override Task Rebuild() { this.DebugDepth("Rebuild"); var rebuildLock = this.RebuildLock(); return(ApplicationController.Instance.Tasks.Execute( "Mirror".Localize(), null, (reporter, cancellationToken) => { SourceContainer.Visible = true; RemoveAllButSource(); var oldMatrix = this.Matrix; this.Matrix = Matrix4X4.Identity; var mirrorMatrix = Matrix4X4.Identity; switch (MirrorOn) { case MirrorAxis.X_Axis: mirrorMatrix = this.ApplyAtBoundsCenter(Matrix4X4.CreateScale(-1, 1, 1)); break; case MirrorAxis.Y_Axis: mirrorMatrix = this.ApplyAtBoundsCenter(Matrix4X4.CreateScale(1, -1, 1)); break; case MirrorAxis.Z_Axis: mirrorMatrix = this.ApplyAtBoundsCenter(Matrix4X4.CreateScale(1, 1, -1)); break; } foreach (var sourceItem in SourceContainer.VisibleMeshes()) { var originalMesh = sourceItem.Mesh; var transformedMesh = originalMesh.Copy(CancellationToken.None); var sourceToThisMatrix = sourceItem.WorldMatrix(this); // move it to us then mirror then move it back transformedMesh.Transform(sourceToThisMatrix * mirrorMatrix * sourceToThisMatrix.Inverted); transformedMesh.ReverseFaces(); var newMesh = new Object3D() { Mesh = transformedMesh }; newMesh.CopyWorldProperties(sourceItem, this, Object3DPropertyFlags.All, false); this.Children.Add(newMesh); } this.Matrix = oldMatrix; SourceContainer.Visible = false; rebuildLock.Dispose(); Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children)); return Task.CompletedTask; })); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); var rebuildLocks = this.RebuilLockAll(); var valuesChanged = false; // check if we have be initialized return(TaskBuilder( "Repair".Localize(), (reporter, cancellationToken) => { SourceContainer.Visible = true; RemoveAllButSource(); var inititialVertices = 0; var inititialFaces = 0; var finalVertices = 0; var finalFaces = 0; foreach (var sourceItem in SourceContainer.VisibleMeshes()) { var originalMesh = sourceItem.Mesh; inititialFaces += originalMesh.Faces.Count; inititialVertices += originalMesh.Vertices.Count; var repairedMesh = Repair(originalMesh, cancellationToken); finalFaces += repairedMesh.Faces.Count; finalVertices += repairedMesh.Vertices.Count; var repairedChild = new Object3D() { Mesh = repairedMesh }; repairedChild.CopyWorldProperties(sourceItem, this, Object3DPropertyFlags.All, false); this.Children.Add(repairedChild); } this.InitialFaces = inititialFaces; this.InitialVertices = inititialVertices; this.FinalFaces = finalFaces; this.FinalVertices = finalVertices; SourceContainer.Visible = false; UiThread.RunOnIdle(() => { rebuildLocks.Dispose(); if (valuesChanged) { Invalidate(InvalidateType.DisplayValues); } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children)); }); return Task.CompletedTask; })); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); var rebuildLocks = this.RebuilLockAll(); var valuesChanged = false; return(TaskBuilder( "Plane Cut".Localize(), (reporter, cancellationToken) => { var newChildren = new List <Object3D>(); var root = SourceContainer.Children.First(); root = root == null ? SourceContainer : root; foreach (var sourceItem in SourceContainer.VisibleMeshes()) { var reducedMesh = Cut(sourceItem); var newMesh = new Object3D() { Mesh = reducedMesh, OwnerID = sourceItem.ID }; newMesh.CopyWorldProperties(sourceItem, root, Object3DPropertyFlags.All); newChildren.Add(newMesh); } var sourceContainer = SourceContainer; this.Children.Modify(list => { list.Clear(); list.Add(sourceContainer); foreach (var child in newChildren) { list.Add(child); } sourceContainer.Visible = false; }); UiThread.RunOnIdle(() => { rebuildLocks.Dispose(); Invalidate(InvalidateType.DisplayValues); Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children)); }); return Task.CompletedTask; })); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); bool valuesChanged = false; // ensure we have good values StartPercent = agg_basics.Clamp(StartPercent, 0, 100, ref valuesChanged); if (Diameter < 1 || Diameter > 100000) { if (Diameter == double.MaxValue) { var aabb = this.GetAxisAlignedBoundingBox(); // uninitialized set to a reasonable value Diameter = (int)aabb.XSize; } Diameter = Math.Min(100000, Math.Max(1, Diameter)); valuesChanged = true; } MinSidesPerRotation = agg_basics.Clamp(MinSidesPerRotation, 3, 360, ref valuesChanged); var rebuildLocks = this.RebuilLockAll(); return(ApplicationController.Instance.Tasks.Execute( "Curve".Localize(), null, (reporter, cancellationToken) => { var sourceAabb = this.SourceContainer.GetAxisAlignedBoundingBox(); var radius = Diameter / 2; var circumference = MathHelper.Tau * radius; double numRotations = sourceAabb.XSize / circumference; double numberOfCuts = numRotations * MinSidesPerRotation; double cutSize = sourceAabb.XSize / numberOfCuts; double cutPosition = sourceAabb.MinXYZ.X + cutSize; var cuts = new List <double>(); for (int i = 0; i < numberOfCuts; i++) { cuts.Add(cutPosition); cutPosition += cutSize; } var rotationCenter = new Vector3(sourceAabb.MinXYZ.X + (sourceAabb.MaxXYZ.X - sourceAabb.MinXYZ.X) * (StartPercent / 100), BendCcw ? sourceAabb.MaxXYZ.Y + radius : sourceAabb.MinXYZ.Y - radius, sourceAabb.Center.Z); var curvedChildren = new List <IObject3D>(); var status = new ProgressStatus(); foreach (var sourceItem in SourceContainer.VisibleMeshes()) { var originalMesh = sourceItem.Mesh; status.Status = "Copy Mesh".Localize(); reporter.Report(status); var transformedMesh = originalMesh.Copy(CancellationToken.None); var itemMatrix = sourceItem.WorldMatrix(SourceContainer); // transform into this space transformedMesh.Transform(itemMatrix); if (SplitMesh) { status.Status = "Split Mesh".Localize(); reporter.Report(status); // split the mesh along the x axis transformedMesh.SplitOnPlanes(Vector3.UnitX, cuts, cutSize / 8); } for (int i = 0; i < transformedMesh.Vertices.Count; i++) { var position = transformedMesh.Vertices[i]; var angleToRotate = ((position.X - rotationCenter.X) / circumference) * MathHelper.Tau - MathHelper.Tau / 4; var distanceFromCenter = rotationCenter.Y - position.Y; if (!BendCcw) { angleToRotate = -angleToRotate; distanceFromCenter = -distanceFromCenter; } var rotatePosition = new Vector3Float(Math.Cos(angleToRotate), Math.Sin(angleToRotate), 0) * distanceFromCenter; rotatePosition.Z = position.Z; transformedMesh.Vertices[i] = rotatePosition + new Vector3Float(rotationCenter.X, radius + sourceAabb.MaxXYZ.Y, 0); } // transform back into item local space transformedMesh.Transform(Matrix4X4.CreateTranslation(-rotationCenter) * itemMatrix.Inverted); if (SplitMesh) { status.Status = "Merge Vertices".Localize(); reporter.Report(status); transformedMesh.MergeVertices(.1); } transformedMesh.CalculateNormals(); var curvedChild = new Object3D() { Mesh = transformedMesh }; curvedChild.CopyWorldProperties(sourceItem, SourceContainer, Object3DPropertyFlags.All, false); curvedChild.Visible = true; curvedChild.Translate(new Vector3(rotationCenter)); if (!BendCcw) { curvedChild.Translate(0, -sourceAabb.YSize - Diameter, 0); } curvedChildren.Add(curvedChild); } RemoveAllButSource(); this.SourceContainer.Visible = false; this.Children.Modify((list) => { list.AddRange(curvedChildren); }); UiThread.RunOnIdle(() => { rebuildLocks.Dispose(); if (valuesChanged) { Invalidate(InvalidateType.DisplayValues); } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children)); }); return Task.CompletedTask; })); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); bool valuesChanged = false; if (Angle < 1 || Angle > 100000) { Angle = Math.Min(100000, Math.Max(1, Angle)); valuesChanged = true; } if (RotationDistance < 0 || RotationDistance > 100000) { RotationDistance = Math.Min(100000, Math.Max(0, RotationDistance)); valuesChanged = true; } if (RotationSlices < 3 || RotationSlices > 300) { RotationSlices = Math.Min(300, Math.Max(3, RotationSlices)); valuesChanged = true; } if (EndHeightPercent < 1 || EndHeightPercent > 100) { EndHeightPercent = Math.Min(100, Math.Max(1, EndHeightPercent)); valuesChanged = true; } if (StartHeightPercent < 0 || StartHeightPercent > EndHeightPercent - 1) { StartHeightPercent = Math.Min(EndHeightPercent - 1, Math.Max(0, StartHeightPercent)); valuesChanged = true; } if (OverrideRadius < .01) { OverrideRadius = Math.Max(this.GetAxisAlignedBoundingBox().XSize, this.GetAxisAlignedBoundingBox().YSize); valuesChanged = true; } var rebuildLocks = this.RebuilLockAll(); return(ApplicationController.Instance.Tasks.Execute( "Twist".Localize(), null, (reporter, cancellationToken) => { var sourceAabb = this.SourceContainer.GetAxisAlignedBoundingBox(); var bottom = sourceAabb.MinXYZ.Z; var top = sourceAabb.ZSize * EndHeightPercent / 100.0; var size = sourceAabb.ZSize; if (Advanced) { bottom += sourceAabb.ZSize * StartHeightPercent / 100.0; size = top - bottom; } double numberOfCuts = RotationSlices; double cutSize = size / numberOfCuts; var cuts = new List <double>(); for (int i = 0; i < numberOfCuts + 1; i++) { var ratio = i / numberOfCuts; if (Advanced) { var goal = ratio; var current = .5; var next = .25; // look for an x value that equals the goal for (int j = 0; j < 64; j++) { var xAtY = Easing.Specify(EasingType, EasingOption, current); if (xAtY < goal) { current += next; } else if (xAtY > goal) { current -= next; } next *= .5; } ratio = current; } cuts.Add(bottom - cutSize + (size * ratio)); } // get the rotation from the center of the circumscribed circle of the convex hull var enclosingCircle = SourceContainer.GetSmallestEnclosingCircleAlongZ(); var rotationCenter = enclosingCircle.Center + RotationOffset; var twistedChildren = new List <IObject3D>(); var status = new ProgressStatus(); foreach (var sourceItem in SourceContainer.VisibleMeshes()) { var originalMesh = sourceItem.Mesh; status.Status = "Copy Mesh".Localize(); reporter.Report(status); var transformedMesh = originalMesh.Copy(CancellationToken.None); var itemMatrix = sourceItem.WorldMatrix(SourceContainer); // transform into this space transformedMesh.Transform(itemMatrix); status.Status = "Split Mesh".Localize(); reporter.Report(status); // split the mesh along the z axis transformedMesh.SplitOnPlanes(Vector3.UnitZ, cuts, cutSize / 8); for (int i = 0; i < transformedMesh.Vertices.Count; i++) { var position = transformedMesh.Vertices[i]; var ratio = (position.Z - bottom) / size; if (Advanced) { if (position.Z < bottom) { ratio = 0; } else if (position.Z > top) { ratio = 1; } else { ratio = (position.Z - bottom) / size; ratio = Easing.Specify(EasingType, EasingOption, ratio); } } var angleToRotate = ratio * Angle / 360.0 * MathHelper.Tau; if (RotationType == RotationTypes.Distance) { IRadiusProvider radiusProvider = RadiusProvider; // start off with assuming we want to set the radius var radius = this.OverrideRadius; if (radiusProvider != null && !this.EditRadius) { // have a radius provider and not wanting to edit radius = radiusProvider.Radius; } else if (!this.EditRadius) { // not wanting to edit radius = enclosingCircle.Radius; } if (this.PreferedRadius != radius) { this.PreferedRadius = radius; this.OverrideRadius = radius; UiThread.RunOnIdle(() => Invalidate(InvalidateType.DisplayValues)); } angleToRotate = ratio * (RotationDistance / radius); } if (!TwistCw) { angleToRotate = -angleToRotate; } var positionXy = new Vector2(position) - rotationCenter; positionXy.Rotate(angleToRotate); positionXy += rotationCenter; transformedMesh.Vertices[i] = new Vector3Float(positionXy.X, positionXy.Y, position.Z); } // transform back into item local space transformedMesh.Transform(itemMatrix.Inverted); //transformedMesh.MergeVertices(.1); transformedMesh.CalculateNormals(); var twistedChild = new Object3D() { Mesh = transformedMesh }; twistedChild.CopyWorldProperties(sourceItem, SourceContainer, Object3DPropertyFlags.All, false); twistedChild.Visible = true; twistedChildren.Add(twistedChild); } RemoveAllButSource(); this.SourceContainer.Visible = false; this.Children.Modify((list) => { list.AddRange(twistedChildren); }); rebuildLocks.Dispose(); if (valuesChanged) { Invalidate(InvalidateType.DisplayValues); } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children)); return Task.CompletedTask; })); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); var rebuildLocks = this.RebuilLockAll(); return(ApplicationController.Instance.Tasks.Execute( "Pinch".Localize(), null, (reporter, cancellationToken) => { SourceContainer.Visible = true; RemoveAllButSource(); // remember the current matrix then clear it so the parts will rotate at the original wrapped position var currentMatrix = Matrix; Matrix = Matrix4X4.Identity; var aabb = SourceContainer.GetAxisAlignedBoundingBox(); bool valuesChanged = false; PinchPercent = agg_basics.Clamp(PinchPercent, 0, 3, ref valuesChanged); foreach (var sourceItem in SourceContainer.VisibleMeshes()) { var originalMesh = sourceItem.Mesh; var transformedMesh = originalMesh.Copy(CancellationToken.None); var itemMatrix = sourceItem.WorldMatrix(SourceContainer); var invItemMatrix = itemMatrix.Inverted; for (int i = 0; i < originalMesh.Vertices.Count; i++) { var pos = originalMesh.Vertices[i]; pos = pos.Transform(itemMatrix); var ratioToApply = PinchPercent / 100.0; var distFromCenter = pos.X - aabb.Center.X; var distanceToPinch = distFromCenter * (1 - ratioToApply); var delta = (aabb.Center.X + distFromCenter * ratioToApply) - pos.X; // find out how much to pinch based on y position var amountOfRatio = (pos.Y - aabb.MinXYZ.Y) / aabb.YSize; var newPos = new Vector3Float(pos.X + delta * amountOfRatio, pos.Y, pos.Z); transformedMesh.Vertices[i] = newPos.Transform(invItemMatrix); } transformedMesh.CalculateNormals(); var newMesh = new Object3D() { Mesh = transformedMesh }; newMesh.CopyWorldProperties(sourceItem, this, Object3DPropertyFlags.All, false); this.Children.Add(newMesh); } // set the matrix back Matrix = currentMatrix; SourceContainer.Visible = false; rebuildLocks.Dispose(); if (valuesChanged) { Invalidate(InvalidateType.DisplayValues); } Invalidate(InvalidateType.Children); return Task.CompletedTask; })); }
private void SubtractAndReplace(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter) { SourceContainer.Visible = true; RemoveAllButSource(); var parentOfPaintTargets = SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf(); if (parentOfPaintTargets.Children.Count() < 2) { if (parentOfPaintTargets.Children.Count() == 1) { this.Children.Add(SourceContainer.Clone()); SourceContainer.Visible = false; } return; } SubtractObject3D_2.CleanUpSelectedChildrenNames(this); var paintObjects = parentOfPaintTargets.Children .Where((i) => SelectedChildren .Contains(i.ID)) .SelectMany(c => c.VisibleMeshes()) .ToList(); var keepItems = parentOfPaintTargets.Children .Where((i) => !SelectedChildren .Contains(i.ID)); var keepVisibleItems = keepItems.SelectMany(c => c.VisibleMeshes()).ToList(); if (paintObjects.Any() && keepVisibleItems.Any()) { var totalOperations = paintObjects.Count * keepVisibleItems.Count; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 0; var progressStatus = new ProgressStatus { Status = "Do CSG" }; foreach (var keep in keepVisibleItems) { var keepResultsMesh = keep.Mesh; var keepWorldMatrix = keep.WorldMatrix(SourceContainer); foreach (var paint in paintObjects) { Mesh paintMesh = BooleanProcessing.Do(keepResultsMesh, keepWorldMatrix, // paint data paint.Mesh, paint.WorldMatrix(SourceContainer), // operation type 2, // reporting data reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); keepResultsMesh = BooleanProcessing.Do(keepResultsMesh, keepWorldMatrix, // point data paint.Mesh, paint.WorldMatrix(SourceContainer), // operation type 1, // reporting data reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); // after the first time we get a result the results mesh is in the right coordinate space keepWorldMatrix = Matrix4X4.Identity; // store our intersection (paint) results mesh var paintResultsItem = new Object3D() { Mesh = paintMesh, Visible = false, OwnerID = paint.ID }; // copy all the properties but the matrix paintResultsItem.CopyWorldProperties(paint, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible))); // and add it to this this.Children.Add(paintResultsItem); // report our progress percentCompleted += amountPerOperation; progressStatus.Progress0To1 = percentCompleted; reporter?.Report(progressStatus); } // store our results mesh var keepResultsItem = new Object3D() { Mesh = keepResultsMesh, Visible = false, OwnerID = keep.ID }; // copy all the properties but the matrix keepResultsItem.CopyWorldProperties(keep, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible))); // and add it to this this.Children.Add(keepResultsItem); } foreach (var child in Children) { child.Visible = true; } SourceContainer.Visible = false; } }
private void Subtract(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter) { SourceContainer.Visible = true; RemoveAllButSource(); var parentOfSubtractTargets = SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf(); if (parentOfSubtractTargets.Children.Count() < 2) { if (parentOfSubtractTargets.Children.Count() == 1) { this.Children.Add(SourceContainer.Clone()); SourceContainer.Visible = false; } return; } CleanUpSelectedChildrenNames(this); var removeVisibleItems = parentOfSubtractTargets.Children .Where((i) => SelectedChildren .Contains(i.Name)) .SelectMany(c => c.VisibleMeshes()) .ToList(); var keepItems = parentOfSubtractTargets.Children .Where((i) => !SelectedChildren .Contains(i.Name)); var keepVisibleItems = keepItems.SelectMany(c => c.VisibleMeshes()).ToList(); if (removeVisibleItems.Any() && keepVisibleItems.Any()) { var totalOperations = removeVisibleItems.Count * keepVisibleItems.Count; double amountPerOperation = 1.0 / totalOperations; double percentCompleted = 0; ProgressStatus progressStatus = new ProgressStatus(); progressStatus.Status = "Do CSG"; foreach (var keep in keepVisibleItems) { var resultsMesh = keep.Mesh; var keepWorldMatrix = keep.WorldMatrix(SourceContainer); foreach (var remove in removeVisibleItems) { resultsMesh = BooleanProcessing.Do(resultsMesh, keepWorldMatrix, remove.Mesh, remove.WorldMatrix(SourceContainer), 1, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); // after the first time we get a result the results mesh is in the right coordinate space keepWorldMatrix = Matrix4X4.Identity; // report our progress percentCompleted += amountPerOperation; progressStatus.Progress0To1 = percentCompleted; reporter?.Report(progressStatus); } // store our results mesh var resultsItem = new Object3D() { Mesh = resultsMesh, Visible = false }; // copy all the properties but the matrix resultsItem.CopyWorldProperties(keep, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible))); // and add it to this this.Children.Add(resultsItem); } bool first = true; foreach (var child in Children) { if (first) { // hid the source item child.Visible = false; first = false; } else { child.Visible = true; } } } }
public override Task Rebuild() { this.DebugDepth("Rebuild"); bool valuesChanged = false; // check if we have initialized the Axis if (Axis.Origin.X == double.NegativeInfinity) { // make it something reasonable (just to the left of the aabb of the object) Axis.Origin = this.GetAxisAlignedBoundingBox().Center; valuesChanged = true; } var rebuildLocks = this.RebuilLockAll(); return(ApplicationController.Instance.Tasks.Execute( "Split".Localize(), null, (reporter, cancellationToken) => { var splitChildren = new List <IObject3D>(); var status = new ProgressStatus(); foreach (var sourceItem in SourceContainer.VisibleMeshes()) { var originalMesh = sourceItem.Mesh; status.Status = "Copy Mesh".Localize(); reporter.Report(status); var transformedMesh = originalMesh.Copy(CancellationToken.None); var itemMatrix = sourceItem.WorldMatrix(SourceContainer); // transform into this space transformedMesh.Transform(itemMatrix); status.Status = "Split Mesh".Localize(); reporter.Report(status); // split faces until they are small enough transformedMesh.Split(Axis.GetPlane()); // transform back into item local space transformedMesh.Transform(itemMatrix.Inverted); var splitChild = new Object3D() { Mesh = transformedMesh }; splitChild.CopyWorldProperties(sourceItem, SourceContainer, Object3DPropertyFlags.All); splitChild.Visible = true; splitChildren.Add(splitChild); } RemoveAllButSource(); this.SourceContainer.Visible = false; this.Children.Modify((list) => { list.AddRange(splitChildren); }); rebuildLocks.Dispose(); if (valuesChanged) { Invalidate(InvalidateType.DisplayValues); } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children)); return Task.CompletedTask; })); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); bool valuesChanged = false; if (MaxEdgeLength < .01) { MaxEdgeLength = Math.Max(.01, MaxEdgeLength); valuesChanged = true; } if (MaxAllowedFaces < 100) { MaxAllowedFaces = Math.Max(100, MaxAllowedFaces); valuesChanged = true; } var rebuildLocks = this.RebuilLockAll(); return(ApplicationController.Instance.Tasks.Execute( "Subdivide".Localize(), null, (reporter, cancellationToken) => { var subdividedChildren = new List <IObject3D>(); var status = new ProgressStatus(); foreach (var sourceItem in SourceContainer.VisibleMeshes()) { var originalMesh = sourceItem.Mesh; status.Status = "Copy Mesh".Localize(); reporter.Report(status); var transformedMesh = originalMesh.Copy(CancellationToken.None); var itemMatrix = sourceItem.WorldMatrix(SourceContainer); // transform into this space transformedMesh.Transform(itemMatrix); status.Status = "Split Mesh".Localize(); reporter.Report(status); // split faces until they are small enough var newVertices = new List <Vector3Float>(); var newFaces = new List <Face>(); for (int i = 0; i < transformedMesh.Faces.Count; i++) { var face = transformedMesh.Faces[i]; SplitRecursive(new Vector3Float[] { transformedMesh.Vertices[face.v0], transformedMesh.Vertices[face.v1], transformedMesh.Vertices[face.v2] }, face.normal, newVertices, newFaces); } transformedMesh.Vertices = newVertices; transformedMesh.Faces = new FaceList(newFaces); // transform back into item local space transformedMesh.Transform(itemMatrix.Inverted); var subdividedChild = new Object3D() { Mesh = transformedMesh }; subdividedChild.CopyWorldProperties(sourceItem, SourceContainer, Object3DPropertyFlags.All); subdividedChild.Visible = true; subdividedChildren.Add(subdividedChild); } RemoveAllButSource(); this.SourceContainer.Visible = false; this.Children.Modify((list) => { list.AddRange(subdividedChildren); }); rebuildLocks.Dispose(); if (valuesChanged) { Invalidate(InvalidateType.DisplayValues); } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children)); return Task.CompletedTask; })); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); bool propertyUpdated = Diameter == double.MinValue; if (StartPercent < 0 || StartPercent > 100) { StartPercent = Math.Min(100, Math.Max(0, StartPercent)); propertyUpdated = true; } var originalAabb = this.GetAxisAlignedBoundingBox(); var rebuildLocks = this.RebuilLockAll(); return(ApplicationController.Instance.Tasks.Execute( "Curve".Localize(), null, (reporter, cancellationToken) => { using (new CenterAndHeightMantainer(this)) { this.Translate(-rotationOffset); SourceContainer.Visible = true; RemoveAllButSource(); // remember the current matrix then clear it so the parts will rotate at the original wrapped position var currentMatrix = Matrix; Matrix = Matrix4X4.Identity; var aabb = this.GetAxisAlignedBoundingBox(); if (Diameter == double.MinValue) { // uninitialized set to a reasonable value Diameter = (int)aabb.XSize; // TODO: ensure that the editor display value is updated } if (Diameter > 0) { var radius = Diameter / 2; var circumference = MathHelper.Tau * radius; var rotationCenter = new Vector3(aabb.MinXYZ.X + (aabb.MaxXYZ.X - aabb.MinXYZ.X) * (StartPercent / 100), aabb.MaxXYZ.Y + radius, aabb.Center.Z); rotationOffset = rotationCenter; if (!BendCcw) { // fix the stored center so we draw correctly rotationOffset.Y = aabb.MinXYZ.Y - radius; } foreach (var sourceItem in SourceContainer.VisibleMeshes()) { var originalMesh = sourceItem.Mesh; var transformedMesh = originalMesh.Copy(CancellationToken.None); var itemMatrix = sourceItem.WorldMatrix(SourceContainer); // split the mesh along the x axis double numRotations = aabb.XSize / circumference; double numberOfCuts = numRotations * MinSidesPerRotation; //SplitMeshAlongX(transformedMesh, numberOfCuts); if (!BendCcw) { // rotate around so it will bend correctly itemMatrix *= Matrix4X4.CreateTranslation(0, -aabb.MaxXYZ.Y, 0); itemMatrix *= Matrix4X4.CreateRotationX(MathHelper.Tau / 2); itemMatrix *= Matrix4X4.CreateTranslation(0, aabb.MaxXYZ.Y - aabb.YSize, 0); } var invItemMatrix = itemMatrix.Inverted; for (int i = 0; i < transformedMesh.Vertices.Count; i++) { var worldPosition = transformedMesh.Vertices[i].Transform((Matrix4X4)itemMatrix); var angleToRotate = ((worldPosition.X - rotationCenter.X) / circumference) * MathHelper.Tau - MathHelper.Tau / 4; var distanceFromCenter = rotationCenter.Y - worldPosition.Y; var rotatePosition = new Vector3Float(Math.Cos(angleToRotate), Math.Sin(angleToRotate), 0) * distanceFromCenter; rotatePosition.Z = worldPosition.Z; var worldWithBend = rotatePosition + new Vector3Float(rotationCenter.X, radius + aabb.MaxXYZ.Y, 0); transformedMesh.Vertices[i] = worldWithBend.Transform(invItemMatrix) - new Vector3Float(rotationOffset); } transformedMesh.MarkAsChanged(); transformedMesh.CalculateNormals(); var newMesh = new Object3D() { Mesh = transformedMesh }; newMesh.CopyWorldProperties(sourceItem, this, Object3DPropertyFlags.All); this.Children.Add(newMesh); } // set the matrix back Matrix = currentMatrix; this.Translate(new Vector3(rotationOffset)); SourceContainer.Visible = false; rebuildLocks.Dispose(); } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children)); } return Task.CompletedTask; })); }
private void Subtract(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter) { SourceContainer.Visible = true; RemoveAllButSource(); var parentOfSubtractTargets = SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf(); if (parentOfSubtractTargets.Children.Count() < 2) { if (parentOfSubtractTargets.Children.Count() == 1) { this.Children.Add(SourceContainer.Clone()); SourceContainer.Visible = false; } return; } CleanUpSelectedChildrenNames(this); var removeVisibleItems = parentOfSubtractTargets.Children .Where((i) => SelectedChildren .Contains(i.ID)) .SelectMany(c => c.VisibleMeshes()) .ToList(); var keepItems = parentOfSubtractTargets.Children .Where((i) => !SelectedChildren .Contains(i.ID)); var keepVisibleItems = keepItems.SelectMany(c => c.VisibleMeshes()).ToList(); if (removeVisibleItems.Any() && keepVisibleItems.Any()) { foreach (var keep in keepVisibleItems) { #if false var items = removeVisibleItems.Select(i => (i.Mesh, i.WorldMatrix(SourceContainer))).ToList(); items.Insert(0, (keep.Mesh, keep.Matrix)); var resultsMesh = BooleanProcessing.DoArray(items, CsgModes.Subtract, Processing, InputResolution, OutputResolution, reporter, cancellationToken); #else var totalOperations = removeVisibleItems.Count * keepVisibleItems.Count; double amountPerOperation = 1.0 / totalOperations; double ratioCompleted = 0; var progressStatus = new ProgressStatus { Status = "Do CSG" }; var resultsMesh = keep.Mesh; var keepWorldMatrix = keep.WorldMatrix(SourceContainer); foreach (var remove in removeVisibleItems) { resultsMesh = BooleanProcessing.Do(resultsMesh, keepWorldMatrix, // other mesh remove.Mesh, remove.WorldMatrix(SourceContainer), // operation type CsgModes.Subtract, Processing, InputResolution, OutputResolution, // reporting reporter, amountPerOperation, ratioCompleted, progressStatus, cancellationToken); // after the first time we get a result the results mesh is in the right coordinate space keepWorldMatrix = Matrix4X4.Identity; // report our progress ratioCompleted += amountPerOperation; progressStatus.Progress0To1 = ratioCompleted; reporter?.Report(progressStatus); } #endif // store our results mesh var resultsItem = new Object3D() { Mesh = resultsMesh, Visible = false, OwnerID = keep.ID }; // copy all the properties but the matrix resultsItem.CopyWorldProperties(keep, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible))); // and add it to this this.Children.Add(resultsItem); if (!RemoveSubtractObjects) { this.Children.Modify((list) => { foreach (var item in removeVisibleItems) { var newObject = new Object3D() { Mesh = item.Mesh }; newObject.CopyWorldProperties(item, SourceContainer, Object3DPropertyFlags.All & (~Object3DPropertyFlags.Visible)); list.Add(newObject); } }); } } bool first = true; foreach (var child in Children) { if (first) { // hide the source item child.Visible = false; first = false; } else { child.Visible = true; } } } }