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