Пример #1
0
        public void DrawEditor(Object3DControlsLayer layer, DrawEventArgs e)
        {
            var diameter            = Diameter.Value(this);
            var startPercent        = StartPercent.Value(this);
            var minSidesPerRotation = MinSidesPerRotation.Value(this);

            var sourceAabb = this.SourceContainer.GetAxisAlignedBoundingBox();
            var distance   = diameter / 2 + sourceAabb.YSize / 2;
            var center     = sourceAabb.Center + new Vector3(0, BendDirection == BendDirections.Bend_Up ? distance : -distance, 0);

            center.X -= sourceAabb.XSize / 2 - (startPercent / 100.0) * sourceAabb.XSize;

            // render the top and bottom rings
            layer.World.RenderCylinderOutline(this.WorldMatrix(), center, diameter, sourceAabb.ZSize, 100, Color.Red, Color.Transparent);

            // render the split lines
            var radius        = diameter / 2;
            var circumference = MathHelper.Tau * radius;
            var xxx           = sourceAabb.XSize * (startPercent / 100.0);
            var startAngle    = MathHelper.Tau * 3 / 4 - xxx / circumference * MathHelper.Tau;

            layer.World.RenderCylinderOutline(this.WorldMatrix(), center, diameter, sourceAabb.ZSize, (int)Math.Max(0, Math.Min(100, minSidesPerRotation)), Color.Transparent, Color.Red, phase: startAngle);

            // turn the lighting back on
            GL.Enable(EnableCap.Lighting);
        }
Пример #2
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");

            bool valuesChanged = false;

            // ensure we have good values
            var startPercent = StartPercent.ClampIfNotCalculated(this, 0, 100, ref valuesChanged);

            var diameter = Diameter.Value(this);

            if (diameter == double.MaxValue ||
                diameter == 0)
            {
                diameter = DiameterFromAngle();
            }

            // keep the unused type synced so we don't change the bend when clicking the tabs
            if (BendType == BendTypes.Diameter)
            {
                AngleFromDiameter();
            }
            else
            {
                diameter = DiameterFromAngle();
            }

            diameter = Diameter.ClampIfNotCalculated(this, .1, 100000, ref valuesChanged);

            var minSidesPerRotation = MinSidesPerRotation.ClampIfNotCalculated(this, 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),
                                                 BendDirection == BendDirections.Bend_Up ? 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 (BendDirection == BendDirections.Bend_Down)
                        {
                            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 (BendDirection == BendDirections.Bend_Down)
                    {
                        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();
                    Invalidate(InvalidateType.DisplayValues);
                    Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
                });

                return Task.CompletedTask;
            }));
        }