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 RadiusUserManager(ICcmUserManager userManager, IRadiusProvider radiusProvider, IUserStore <CcmUser> store) : base(store) { _ccmUserManager = userManager; _radiusProvider = radiusProvider; }