Esempio n. 1
0
        private void Rebuild(UndoBuffer undoBuffer)
        {
            this.DebugDepth("Rebuild");
            using (RebuildLock())
            {
                var aabb = this.GetAxisAlignedBoundingBox();

                var path = new VertexStorage();
                path.MoveTo(Width / 2, 0);

                for (int i = 1; i < Sides; i++)
                {
                    var angle = MathHelper.Tau * i / 2 / (Sides - 1);
                    path.LineTo(Math.Cos(angle) * Width / 2, Math.Sin(angle) * Width / 2);
                }

                var mesh = VertexSourceToMesh.Extrude(path, Depth);
                mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4));
                Mesh = mesh;

                if (aabb.ZSize > 0)
                {
                    // If the part was already created and at a height, maintain the height.
                    PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
                }
            }

            Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
        }
Esempio n. 2
0
        private void CreateBase(List <MeshGroup> meshesList, List <Matrix4X4> meshTransforms, List <PlatingMeshGroupData> platingDataList)
        {
            if (meshesList.Count > 0)
            {
                AxisAlignedBoundingBox bounds = meshesList[0].GetAxisAlignedBoundingBox(meshTransforms[0]);
                for (int i = 1; i < meshesList.Count; i++)
                {
                    bounds = AxisAlignedBoundingBox.Union(bounds, meshesList[i].GetAxisAlignedBoundingBox(meshTransforms[i]));
                }

                double          roundingScale = 20;
                RectangleDouble baseRect      = new RectangleDouble(bounds.minXYZ.x, bounds.minXYZ.y, bounds.maxXYZ.x, bounds.maxXYZ.y);
                baseRect.Inflate(2);
                baseRect *= roundingScale;
                RoundedRect baseRoundedRect = new RoundedRect(baseRect, 1 * roundingScale);

                Mesh baseMeshResult = VertexSourceToMesh.Extrude(baseRoundedRect, unscaledBaseHeight / 2 * roundingScale * sizeScrollBar.Value * heightScrollBar.Value);

                baseMeshResult.Transform(Matrix4X4.CreateScale(1 / roundingScale));

                meshesList.Add(new MeshGroup(baseMeshResult));
                platingDataList.Add(new PlatingMeshGroupData());
                meshTransforms.Add(Matrix4X4.CreateTranslation(0, 0, 0));
                PlatingHelper.CreateITraceableForMeshGroup(platingDataList, meshesList, meshesList.Count - 1, null);
            }
        }
        private void AddCharacterMeshes(string currentText, TypeFacePrinter printer)
        {
            int            newIndex = asynchMeshGroups.Count;
            StyledTypeFace typeFace = printer.TypeFaceStyle;

            for (int i = 0; i < currentText.Length; i++)
            {
                string          letter        = currentText[i].ToString();
                TypeFacePrinter letterPrinter = new TypeFacePrinter(letter, typeFace);

                if (CharacterHasMesh(letterPrinter, letter))
                {
                    Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2);

                    asynchMeshGroups.Add(new MeshGroup(textMesh));

                    PlatingMeshGroupData newMeshInfo = new PlatingMeshGroupData();

                    newMeshInfo.spacing = printer.GetOffsetLeftOfCharacterIndex(i);
                    asynchPlatingDatas.Add(newMeshInfo);
                    asynchMeshGroupTransforms.Add(ScaleRotateTranslate.Identity());

                    PlatingHelper.CreateITraceableForMeshGroup(asynchPlatingDatas, asynchMeshGroups, newIndex, null);
                    ScaleRotateTranslate moved = asynchMeshGroupTransforms[newIndex];
                    moved.translation *= Matrix4X4.CreateTranslation(new Vector3(0, 0, unscaledLetterHeight / 2));
                    asynchMeshGroupTransforms[newIndex] = moved;

                    newIndex++;
                }

                processingProgressControl.PercentComplete = ((i + 1) * 95 / currentText.Length);
            }
        }
Esempio n. 4
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");
            bool valuesChanged = false;

            using (RebuildLock())
            {
                var sides = Sides.ClampIfNotCalculated(this, 3, 180, ref valuesChanged);
                using (new CenterAndHeightMaintainer(this))
                {
                    var path = new VertexStorage();
                    path.MoveTo(Width.Value(this) / 2, 0);

                    for (int i = 1; i < sides; i++)
                    {
                        var angle = MathHelper.Tau * i / 2 / (sides - 1);
                        path.LineTo(Math.Cos(angle) * Width.Value(this) / 2, Math.Sin(angle) * Width.Value(this) / 2);
                    }

                    var mesh = VertexSourceToMesh.Extrude(path, Depth.Value(this));
                    mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4));
                    Mesh = mesh;
                }
            }

            Invalidate(InvalidateType.DisplayValues);

            Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
            return(Task.CompletedTask);
        }
Esempio n. 5
0
        private void Rebuild(UndoBuffer undoBuffer)
        {
            this.DebugDepth("Rebuild");
            bool changed = false;

            using (RebuildLock())
            {
                InnerDiameter = agg_basics.Clamp(InnerDiameter, 0, OuterDiameter - .1, ref changed);
                Sides         = agg_basics.Clamp(Sides, 3, 360, ref changed);
                RingSides     = agg_basics.Clamp(RingSides, 3, 360, ref changed);

                var ringSides      = RingSides;
                var startingAngle  = StartingAngle;
                var endingAngle    = EndingAngle;
                var ringPhaseAngle = RingPhaseAngle;
                if (!Advanced)
                {
                    ringSides      = Math.Max(3, (int)(Sides / 2));
                    startingAngle  = 0;
                    endingAngle    = 360;
                    ringPhaseAngle = 0;
                }

                var innerDiameter = Math.Min(OuterDiameter - .1, InnerDiameter);

                var aabb = this.GetAxisAlignedBoundingBox();

                var poleRadius     = (OuterDiameter / 2 - innerDiameter / 2) / 2;
                var toroidRadius   = innerDiameter / 2 + poleRadius;
                var path           = new VertexStorage();
                var angleDelta     = MathHelper.Tau / ringSides;
                var ringStartAngle = MathHelper.DegreesToRadians(ringPhaseAngle);
                var ringAngle      = ringStartAngle;
                var circleCenter   = new Vector2(toroidRadius, 0);
                path.MoveTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringStartAngle), poleRadius * Math.Sin(ringStartAngle)));
                for (int i = 0; i < ringSides - 1; i++)
                {
                    ringAngle += angleDelta;
                    path.LineTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringAngle), poleRadius * Math.Sin(ringAngle)));
                }

                path.LineTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringStartAngle), poleRadius * Math.Sin(ringStartAngle)));

                var startAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(startingAngle));
                var endAngle   = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(endingAngle));
                Mesh = VertexSourceToMesh.Revolve(path, Sides, startAngle, endAngle);

                if (aabb.ZSize > 0)
                {
                    // If the part was already created and at a height, maintain the height.
                    PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
                }
            }

            Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
            if (changed)
            {
                base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
            }
        }
        protected IObject3D CreateReach(double reach, double innerDiameter)
        {
            var finWidth  = 4.0;
            var finLength = innerDiameter;

            var pattern = new VertexStorage();

            pattern.MoveTo(0, 0);
            pattern.LineTo(finLength / 2, 0);
            pattern.LineTo(finLength / 2, reach - finLength / 8);
            pattern.LineTo(finLength / 2 - finLength / 8, reach);
            pattern.LineTo(-finLength / 2 + finLength / 8, reach);
            pattern.LineTo(-finLength / 2, reach - finLength / 8);
            pattern.LineTo(-finLength / 2, 0);

            var fin1 = new Object3D()
            {
                Mesh = VertexSourceToMesh.Extrude(pattern, finWidth)
            };

            fin1 = new TranslateObject3D(fin1, 0, 0, -finWidth / 2);
            //fin1.ChamferEdge(Face.Top | Face.Back, finLength / 8);
            //fin1.ChamferEdge(Face.Top | Face.Front, finLength / 8);
            fin1 = new RotateObject3D(fin1, -MathHelper.Tau / 4);
            var fin2 = new SetCenterObject3D(new RotateObject3D(fin1, 0, 0, MathHelper.Tau / 4), fin1.GetCenter());

            return(new Object3D().SetChildren(new List <IObject3D>()
            {
                fin1, fin2
            }));
        }
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");
            bool valuesChanged = false;

            using (RebuildLock())
            {
                InnerDiameter = agg_basics.Clamp(InnerDiameter, 0, OuterDiameter - .1, ref valuesChanged);
                Sides         = agg_basics.Clamp(Sides, 3, 360, ref valuesChanged);
                RingSides     = agg_basics.Clamp(RingSides, 3, 360, ref valuesChanged);

                StartingAngle = agg_basics.Clamp(StartingAngle, 0, 360 - .01, ref valuesChanged);
                EndingAngle   = agg_basics.Clamp(EndingAngle, StartingAngle + .01, 360, ref valuesChanged);

                var ringSides      = RingSides;
                var startingAngle  = StartingAngle;
                var endingAngle    = EndingAngle;
                var ringPhaseAngle = RingPhaseAngle;
                if (!Advanced)
                {
                    ringSides      = Math.Max(3, (int)(Sides / 2));
                    startingAngle  = 0;
                    endingAngle    = 360;
                    ringPhaseAngle = 0;
                }

                var innerDiameter = Math.Min(OuterDiameter - .1, InnerDiameter);

                using (new CenterAndHeightMaintainer(this))
                {
                    var poleRadius     = (OuterDiameter / 2 - innerDiameter / 2) / 2;
                    var toroidRadius   = innerDiameter / 2 + poleRadius;
                    var path           = new VertexStorage();
                    var angleDelta     = MathHelper.Tau / ringSides;
                    var ringStartAngle = MathHelper.DegreesToRadians(ringPhaseAngle);
                    var ringAngle      = ringStartAngle;
                    var circleCenter   = new Vector2(toroidRadius, 0);
                    path.MoveTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringStartAngle), poleRadius * Math.Sin(ringStartAngle)));
                    for (int i = 0; i < ringSides - 1; i++)
                    {
                        ringAngle += angleDelta;
                        path.LineTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringAngle), poleRadius * Math.Sin(ringAngle)));
                    }

                    path.LineTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringStartAngle), poleRadius * Math.Sin(ringStartAngle)));

                    var startAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(startingAngle));
                    var endAngle   = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(endingAngle));
                    Mesh = VertexSourceToMesh.Revolve(path, Sides, startAngle, endAngle);
                }
            }

            if (valuesChanged)
            {
                Invalidate(InvalidateType.DisplayValues);
            }

            Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
            return(Task.CompletedTask);
        }
Esempio n. 8
0
        private void Rebuild(UndoBuffer undoBuffer)
        {
            this.DebugDepth("Rebuild");
            bool changed = false;

            using (RebuildLock())
            {
                Sides = agg_basics.Clamp(Sides, 3, 360, ref changed);
                var aabb = this.GetAxisAlignedBoundingBox();

                var path = new VertexStorage();
                path.MoveTo(0, 0);
                path.LineTo(Diameter / 2, 0);
                path.LineTo(0, Height);

                Mesh = VertexSourceToMesh.Revolve(path, Sides);
                if (aabb.ZSize > 0)
                {
                    // If the part was already created and at a height, maintain the height.
                    PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
                }
            }

            Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
            if (changed)
            {
                base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
            }
        }
Esempio n. 9
0
        private void insertTextBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
            BackgroundWorker backgroundWorker = (BackgroundWorker)sender;

            asynchMeshGroups.Clear();
            asynchMeshGroupTransforms.Clear();
            asynchPlatingDatas.Clear();

            string          currentText  = (string)e.Argument;
            TypeFacePrinter printer      = new TypeFacePrinter(currentText, new StyledTypeFace(boldTypeFace, 12));
            Vector2         size         = printer.GetSize(currentText);
            double          centerOffset = -size.x / 2;

            double ratioPerMeshGroup = 1.0 / currentText.Length;
            double currentRatioDone  = 0;

            for (int i = 0; i < currentText.Length; i++)
            {
                int newIndex = asynchMeshGroups.Count;

                TypeFacePrinter letterPrinter = new TypeFacePrinter(currentText[i].ToString(), new StyledTypeFace(boldTypeFace, 12));
                Mesh            textMesh      = VertexSourceToMesh.Extrude(letterPrinter, 10 + (i % 2));

                if (textMesh.Faces.Count > 0)
                {
                    asynchMeshGroups.Add(new MeshGroup(textMesh));

                    PlatingMeshGroupData newMeshInfo = new PlatingMeshGroupData();

                    newMeshInfo.xSpacing = printer.GetOffsetLeftOfCharacterIndex(i).x + centerOffset;
                    asynchPlatingDatas.Add(newMeshInfo);
                    asynchMeshGroupTransforms.Add(ScaleRotateTranslate.Identity());

                    PlatingHelper.CreateITraceableForMeshGroup(asynchPlatingDatas, asynchMeshGroups, newIndex, (double progress0To1, string processingState, out bool continueProcessing) =>
                    {
                        continueProcessing = true;
                        int nextPercent    = (int)((currentRatioDone + ratioPerMeshGroup * progress0To1) * 100);
                        backgroundWorker.ReportProgress(nextPercent);
                    });

                    currentRatioDone += ratioPerMeshGroup;

                    PlatingHelper.PlaceMeshGroupOnBed(asynchMeshGroups, asynchMeshGroupTransforms, newIndex);
                }

                backgroundWorker.ReportProgress((i + 1) * 95 / currentText.Length);
            }

            SetWordSpacing(asynchMeshGroups, asynchMeshGroupTransforms, asynchPlatingDatas);
            SetWordSize(asynchMeshGroups, asynchMeshGroupTransforms);
            SetWordHeight(asynchMeshGroups, asynchMeshGroupTransforms);

            if (createUnderline.Checked)
            {
                CreateUnderline(asynchMeshGroups, asynchMeshGroupTransforms, asynchPlatingDatas);
            }

            backgroundWorker.ReportProgress(95);
        }
        private void Rebuild(UndoBuffer undoBuffer)
        {
            this.DebugDepth("Rebuild");
            using (RebuildLock())
            {
                var aabb = this.GetAxisAlignedBoundingBox();

                var radius     = Diameter / 2;
                var angleDelta = MathHelper.Tau / 4 / LatitudeSides;
                var angle      = 0.0;
                var path       = new VertexStorage();
                path.MoveTo(0, 0);
                path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
                for (int i = 0; i < LatitudeSides; i++)
                {
                    angle += angleDelta;
                    path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
                }

                Mesh = VertexSourceToMesh.Revolve(path, LongitudeSides);
                if (aabb.ZSize > 0)
                {
                    // If the part was already created and at a height, maintain the height.
                    PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
                }
            }

            Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
        }
Esempio n. 11
0
        public void GenerateBase(Polygons polygonShape, double bottomWithoutBase)
        {
            if (polygonShape != null &&
                polygonShape.Select(p => p.Count).Sum() > 3)
            {
                Polygons polysToOffset = new Polygons();

                switch (BaseType)
                {
                case BaseTypes.Rectangle:
                    polysToOffset.Add(GetBoundingPolygon(polygonShape));
                    break;

                case BaseTypes.Circle:
                    polysToOffset.Add(GetBoundingCircle(polygonShape));
                    break;

                case BaseTypes.Outline:
                    PolyTree polyTreeForBase = GetPolyTree(polygonShape);
                    foreach (PolyNode polyToOffset in polyTreeForBase.Childs)
                    {
                        polysToOffset.Add(polyToOffset.Contour);
                    }
                    break;
                }

                if (polysToOffset.Count > 0)
                {
                    Polygons basePolygons;

                    if (BaseType == BaseTypes.Outline &&
                        InfillAmount > 0)
                    {
                        basePolygons = Offset(polysToOffset, (BaseSize + InfillAmount) * scalingForClipper);
                        basePolygons = Offset(basePolygons, -InfillAmount * scalingForClipper);
                    }
                    else
                    {
                        basePolygons = Offset(polysToOffset, BaseSize * scalingForClipper);
                    }

                    basePolygons = ClipperLib.Clipper.CleanPolygons(basePolygons, 10);

                    VertexStorage rawVectorShape = basePolygons.PolygonToPathStorage();
                    var           vectorShape    = new VertexSourceApplyTransform(rawVectorShape, Affine.NewScaling(1.0 / scalingForClipper));

                    var baseObject = new Object3D()
                    {
                        Mesh = VertexSourceToMesh.Extrude(vectorShape, zHeight: ExtrusionHeight)
                    };
                    Children.Add(baseObject);
                    baseObject.Mesh.Translate(new Vector3(0, 0, -ExtrusionHeight + bottomWithoutBase));
                }
                else
                {
                    // clear the mesh
                    Mesh = null;
                }
            }
        }
Esempio n. 12
0
        private void Rebuild(UndoBuffer undoBuffer)
        {
            this.DebugDepth("Rebuild");
            using (RebuildLock())
            {
                var aabb = this.GetAxisAlignedBoundingBox();

                var path = new VertexStorage();
                path.MoveTo(0, 0);
                path.LineTo(Math.Sqrt(2), 0);
                path.LineTo(0, Height);

                var mesh = VertexSourceToMesh.Revolve(path, 4);
                mesh.Transform(Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(45)) * Matrix4X4.CreateScale(Width / 2, Depth / 2, 1));
                Mesh = mesh;

                if (aabb.ZSize > 0)
                {
                    // If the part was already created and at a height, maintain the height.
                    PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
                }
            }

            Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
        }
Esempio n. 13
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");
            var rebuildLock = RebuildLock();

            bool valuesChanged = false;

            var height = Height.Value(this);

#if DEBUG
            var bevelSteps = BevelSteps.ClampIfNotCalculated(this, 1, 32, ref valuesChanged);
            var bevelStart = BevelStart.ClampIfNotCalculated(this, 0, height, ref valuesChanged);
            var aabb       = this.GetAxisAlignedBoundingBox();
            var bevelInset = BevelInset.ClampIfNotCalculated(this, 0, Math.Min(aabb.XSize / 2, aabb.YSize / 2), ref valuesChanged);
#endif

            // now create a long running task to do the extrusion
            return(ApplicationController.Instance.Tasks.Execute(
                       "Linear Extrude".Localize(),
                       null,
                       (reporter, cancellationToken) =>
            {
                var vertexSource = this.VertexSource;
                List <(double height, double inset)> bevel = null;
#if DEBUG
                if (BevelTop)
                {
                    bevel = new List <(double height, double inset)>();
                    for (int i = 0; i < bevelSteps; i++)
                    {
                        var heightRatio = i / (double)bevelSteps;
                        height = heightRatio * (height - bevelStart) + bevelStart;
                        var insetRatio = (i + 1) / (double)bevelSteps;
                        var inset = Easing.Sinusoidal.In(insetRatio) * -bevelInset;
                        bevel.Add((height, inset));
                    }
                }
#endif

                Mesh = VertexSourceToMesh.Extrude(this.VertexSource, height, bevel);
                if (Mesh.Vertices.Count == 0)
                {
                    Mesh = null;
                }

                UiThread.RunOnIdle(() =>
                {
                    rebuildLock.Dispose();
                    if (valuesChanged)
                    {
                        Invalidate(InvalidateType.DisplayValues);
                    }
                    Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
                });

                return Task.CompletedTask;
            }));
        }
Esempio n. 14
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");

            var rebuildLock = RebuildLock();

            return(Task.Run(() =>
            {
                using (new CenterAndHeightMaintainer(this))
                {
                    bool valuesChanged = false;
                    var height = Height.ClampIfNotCalculated(this, .01, 1000000, ref valuesChanged);
                    var nameToWrite = NameToWrite.Value(this);
                    if (string.IsNullOrWhiteSpace(nameToWrite))
                    {
                        Mesh = PlatonicSolids.CreateCube(20, 10, height);
                    }
                    else
                    {
                        Mesh = null;
                        this.Children.Modify(list =>
                        {
                            list.Clear();

                            var offest = 0.0;
                            double pointsToMm = 0.352778;

                            foreach (var letter in nameToWrite.ToCharArray())
                            {
                                var style = new StyledTypeFace(ApplicationController.GetTypeFace(this.Font), PointSize.Value(this));
                                var letterPrinter = new TypeFacePrinter(letter.ToString(), style)
                                {
                                    ResolutionScale = 10
                                };
                                var scaledLetterPrinter = new VertexSourceApplyTransform(letterPrinter, Affine.NewScaling(pointsToMm));

                                list.Add(new Object3D()
                                {
                                    Mesh = VertexSourceToMesh.Extrude(scaledLetterPrinter, this.Height.Value(this)),
                                    Matrix = Matrix4X4.CreateTranslation(offest, 0, 0),
                                    Name = letter.ToString()
                                });

                                offest += letterPrinter.GetSize(letter.ToString()).X *pointsToMm;
                            }
                        });
                    }
                }

                UiThread.RunOnIdle(() =>
                {
                    rebuildLock.Dispose();
                    Invalidate(InvalidateType.DisplayValues);
                    Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
                });
            }));
        }
Esempio n. 15
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");
            bool valuesChanged = false;

            var startingAngle = StartingAngle.ClampIfNotCalculated(this, 0, 360 - .01, ref valuesChanged);
            var endingAngle   = EndingAngle.ClampIfNotCalculated(this, startingAngle + .01, 360, ref valuesChanged);
            var sides         = Sides.Value(this);
            var axisPosition  = AxisPosition.Value(this);

            if (startingAngle > 0 || endingAngle < 360)
            {
                Sides = agg_basics.Clamp(sides, 1, 360, ref valuesChanged);
            }
            else
            {
                Sides = agg_basics.Clamp(sides, 3, 360, ref valuesChanged);
            }

            Invalidate(InvalidateType.DisplayValues);

            var rebuildLock = RebuildLock();

            // now create a long running task to process the image
            return(ApplicationController.Instance.Tasks.Execute(
                       "Revolve".Localize(),
                       null,
                       (reporter, cancellationToken) =>
            {
                var vertexSource = this.VertexSource;
                var pathBounds = vertexSource.GetBounds();
                vertexSource = vertexSource.Translate(-pathBounds.Left - axisPosition, 0);
                Mesh mesh = VertexSourceToMesh.Revolve(vertexSource,
                                                       sides,
                                                       MathHelper.DegreesToRadians(360 - endingAngle),
                                                       MathHelper.DegreesToRadians(360 - startingAngle),
                                                       false);

                // take the axis offset out
                mesh.Transform(Matrix4X4.CreateTranslation(pathBounds.Left + axisPosition, 0, 0));

                if (mesh.Vertices.Count == 0)
                {
                    mesh = null;
                }

                Mesh = mesh;

                UiThread.RunOnIdle(() =>
                {
                    rebuildLock.Dispose();
                    Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
                });

                return Task.CompletedTask;
            }));
        }
Esempio n. 16
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");
            bool valuesChanged = false;

            StartingAngle = agg_basics.Clamp(StartingAngle, 0, 360 - .01, ref valuesChanged);
            EndingAngle   = agg_basics.Clamp(EndingAngle, StartingAngle + .01, 360, ref valuesChanged);

            if (StartingAngle > 0 || EndingAngle < 360)
            {
                Sides = agg_basics.Clamp(Sides, 1, 360, ref valuesChanged);
            }
            else
            {
                Sides = agg_basics.Clamp(Sides, 3, 360, ref valuesChanged);
            }

            if (valuesChanged)
            {
                Invalidate(InvalidateType.DisplayValues);
            }

            var rebuildLock = RebuildLock();

            // now create a long running task to process the image
            return(ApplicationController.Instance.Tasks.Execute(
                       "Revolve".Localize(),
                       null,
                       (reporter, cancellationToken) =>
            {
                var vertexSource = this.VertexSource.Transform(Matrix);
                var pathBounds = vertexSource.GetBounds();
                vertexSource = vertexSource.Translate(-pathBounds.Left - AxisPosition, 0);
                Mesh mesh = VertexSourceToMesh.Revolve(vertexSource,
                                                       Sides,
                                                       MathHelper.DegreesToRadians(360 - EndingAngle),
                                                       MathHelper.DegreesToRadians(360 - StartingAngle),
                                                       false);

                // take the axis offset out
                mesh.Transform(Matrix4X4.CreateTranslation(pathBounds.Left + AxisPosition, 0, 0));
                // move back to object space
                mesh.Transform(this.Matrix.Inverted);

                if (mesh.Vertices.Count == 0)
                {
                    mesh = null;
                }

                Mesh = mesh;

                rebuildLock.Dispose();
                Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
                return Task.CompletedTask;
            }));
        }
Esempio n. 17
0
        private void Rebuild(UndoBuffer undoBuffer)
        {
            this.DebugDepth("Rebuild");
            bool changed = false;

            using (RebuildLock())
            {
                Sides         = agg_basics.Clamp(Sides, 3, 360, ref changed);
                LatitudeSides = agg_basics.Clamp(LatitudeSides, 3, 360, ref changed);

                var aabb = this.GetAxisAlignedBoundingBox();

                var startingAngle = StartingAngle;
                var endingAngle   = EndingAngle;
                var latitudeSides = LatitudeSides;
                if (!Advanced)
                {
                    startingAngle = 0;
                    endingAngle   = 360;
                    latitudeSides = Sides;
                }

                var path       = new VertexStorage();
                var angleDelta = MathHelper.Tau / 2 / latitudeSides;
                var angle      = -MathHelper.Tau / 4;
                var radius     = Diameter / 2;
                path.MoveTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
                for (int i = 0; i < latitudeSides; i++)
                {
                    angle += angleDelta;
                    path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
                }

                var startAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(startingAngle));
                var endAngle   = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(endingAngle));
                var steps      = Math.Max(1, (int)(Sides * MathHelper.Tau / Math.Abs(MathHelper.GetDeltaAngle(startAngle, endAngle)) + .5));
                Mesh = VertexSourceToMesh.Revolve(path,
                                                  steps,
                                                  startAngle,
                                                  endAngle);
                if (aabb.ZSize > 0)
                {
                    // If the part was already created and at a height, maintain the height.
                    PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
                }
            }

            Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));

            if (changed)
            {
                base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
            }
        }
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");

            bool valuesChanged = false;

            if (BevelTop)
            {
                BevelSteps = agg_basics.Clamp(BevelSteps, 1, 32, ref valuesChanged);
                BevelStart = agg_basics.Clamp(BevelStart, 0, Height, ref valuesChanged);
                var aabb = this.GetAxisAlignedBoundingBox();
                BevelInset = agg_basics.Clamp(BevelInset, 0, Math.Min(aabb.XSize / 2, aabb.YSize / 2), ref valuesChanged);
            }

            var rebuildLock = RebuildLock();

            // now create a long running task to process the image
            return(ApplicationController.Instance.Tasks.Execute(
                       "Linear Extrude".Localize(),
                       null,
                       (reporter, cancellationToken) =>
            {
                var vertexSource = this.VertexSource;
                List <(double height, double inset)> bevel = null;
                if (BevelTop)
                {
                    bevel = new List <(double height, double inset)>();
                    for (int i = 0; i < BevelSteps; i++)
                    {
                        var heightRatio = i / (double)BevelSteps;
                        var height = heightRatio * (Height - BevelStart) + BevelStart;
                        var insetRatio = (i + 1) / (double)BevelSteps;
                        var inset = Easing.Sinusoidal.In(insetRatio) * -BevelInset;
                        bevel.Add((height, inset));
                    }
                }

                Mesh = VertexSourceToMesh.Extrude(this.VertexSource, Height, bevel);
                if (Mesh.Vertices.Count == 0)
                {
                    Mesh = null;
                }

                rebuildLock.Dispose();

                if (valuesChanged)
                {
                    Invalidate(InvalidateType.DisplayValues);
                }

                Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
                return Task.CompletedTask;
            }));
        }
        // TODO: EditorTools owns this, move to more general location
        private static Mesh CreateCylinder(double height = 20, double radius = 10, int rotationCount = 30)
        {
            var path = new VertexStorage();

            path.MoveTo(0, 0);
            path.LineTo(radius, 0);
            path.LineTo(radius, height);
            path.LineTo(0, height);

            return(VertexSourceToMesh.Revolve(path, rotationCount));
        }
Esempio n. 20
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");

            var rebuildLock = RebuildLock();

            return(ApplicationController.Instance.Tasks.Execute(
                       "Generating Text Meshes".Localize(),
                       null,
                       (reporter, cancellationToken) =>
            {
                using (new CenterAndHeightMaintainer(this))
                {
                    if (string.IsNullOrWhiteSpace(NameToWrite))
                    {
                        Mesh = PlatonicSolids.CreateCube(20, 10, Height);
                    }
                    else
                    {
                        Mesh = null;
                        this.Children.Modify(list =>
                        {
                            list.Clear();

                            var offest = 0.0;
                            double pointsToMm = 0.352778;

                            foreach (var letter in this.NameToWrite.ToCharArray())
                            {
                                var letterPrinter = new TypeFacePrinter(letter.ToString(), new StyledTypeFace(ApplicationController.GetTypeFace(this.Font), this.PointSize))
                                {
                                    ResolutionScale = 10
                                };
                                var scaledLetterPrinter = new VertexSourceApplyTransform(letterPrinter, Affine.NewScaling(pointsToMm));

                                list.Add(new Object3D()
                                {
                                    Mesh = VertexSourceToMesh.Extrude(scaledLetterPrinter, this.Height),
                                    Matrix = Matrix4X4.CreateTranslation(offest, 0, 0),
                                    Name = letter.ToString()
                                });

                                offest += letterPrinter.GetSize(letter.ToString()).X *pointsToMm;
                            }
                        });
                    }
                }

                rebuildLock.Dispose();
                Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
                return Task.CompletedTask;
            }));
        }
Esempio n. 21
0
        private void AddCharacterMeshes(string currentText, TypeFacePrinter printer)
        {
            int            newIndex = asyncMeshGroups.Count;
            StyledTypeFace typeFace = printer.TypeFaceStyle;

            for (int i = 0; i < currentText.Length; i++)
            {
                string          letter        = currentText[i].ToString();
                TypeFacePrinter letterPrinter = new TypeFacePrinter(letter, typeFace);

                if (CharacterHasMesh(letterPrinter, letter))
                {
#if true
                    Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2);
#else
                    Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2);
                    // this is the code to make rounded tops
                    // convert the letterPrinter to clipper polygons
                    List <List <IntPoint> > insetPoly = VertexSourceToPolygon.CreatePolygons(letterPrinter);
                    // inset them
                    ClipperOffset clipper = new ClipperOffset();
                    clipper.AddPaths(insetPoly, JoinType.jtMiter, EndType.etClosedPolygon);
                    List <List <IntPoint> > solution = new List <List <IntPoint> >();
                    clipper.Execute(solution, 5.0);
                    // convert them back into a vertex source
                    // merge both the inset and original vertex sources together
                    // convert the new vertex source into a mesh (trianglulate them)
                    // offset the inner loop in z
                    // create the polygons from the inner loop to a center point so that there is the rest of an approximation of the bubble
                    // make the mesh for the bottom
                    // add the top and bottom together
                    // done
#endif

                    asyncMeshGroups.Add(new MeshGroup(textMesh));

                    PlatingMeshGroupData newMeshInfo = new PlatingMeshGroupData();

                    newMeshInfo.spacing = printer.GetOffsetLeftOfCharacterIndex(i);
                    asyncPlatingDatas.Add(newMeshInfo);
                    asyncMeshGroupTransforms.Add(ScaleRotateTranslate.Identity());

                    PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, newIndex, null);
                    ScaleRotateTranslate moved = asyncMeshGroupTransforms[newIndex];
                    moved.translation *= Matrix4X4.CreateTranslation(new Vector3(0, 0, unscaledLetterHeight / 2));
                    asyncMeshGroupTransforms[newIndex] = moved;

                    newIndex++;
                }

                processingProgressControl.PercentComplete = ((i + 1) * 95 / currentText.Length);
            }
        }
Esempio n. 22
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");
            bool valuesChanged = false;

            var roundSegments = RoundSegments.ClampIfNotCalculated(this, 2, 90, ref valuesChanged);

            Invalidate(InvalidateType.DisplayValues);

            using (RebuildLock())
            {
                var height = Height.Value(this);
                var width  = Width.Value(this);
                using (new CenterAndHeightMaintainer(this))
                {
                    var path = new VertexStorage();
                    path.MoveTo(0, 0);
                    path.LineTo(width, 0);

                    var range = 360 / 4.0;
                    switch (Round)
                    {
                    case RoundTypes.Up:
                        for (int i = 1; i < roundSegments - 1; i++)
                        {
                            var angle = range / (roundSegments - 1) * i;
                            var rad   = MathHelper.DegreesToRadians(angle);
                            path.LineTo(Math.Cos(rad) * width, Math.Sin(rad) * height);
                        }
                        break;

                    case RoundTypes.Down:
                        for (int i = 1; i < roundSegments - 1; i++)
                        {
                            var angle = range / (roundSegments - 1) * i;
                            var rad   = MathHelper.DegreesToRadians(angle);
                            path.LineTo(width - Math.Sin(rad) * width, height - Math.Cos(rad) * height);
                        }
                        break;
                    }

                    path.LineTo(0, height);

                    Mesh = VertexSourceToMesh.Extrude(path, Depth.Value(this));
                    Mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4));
                }
            }

            Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));

            return(Task.CompletedTask);
        }
Esempio n. 23
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");
            bool valuesChanged = false;

            using (RebuildLock())
            {
                Sides         = agg_basics.Clamp(Sides, 3, 360, ref valuesChanged);
                LatitudeSides = agg_basics.Clamp(LatitudeSides, 3, 360, ref valuesChanged);

                using (new CenterAndHeightMaintainer(this))
                {
                    var startingAngle = StartingAngle;
                    var endingAngle   = EndingAngle;
                    var latitudeSides = LatitudeSides;
                    if (!Advanced)
                    {
                        startingAngle = 0;
                        endingAngle   = 360;
                        latitudeSides = Sides;
                    }

                    var path       = new VertexStorage();
                    var angleDelta = MathHelper.Tau / 2 / latitudeSides;
                    var angle      = -MathHelper.Tau / 4;
                    var radius     = Diameter / 2;
                    path.MoveTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
                    for (int i = 0; i < latitudeSides; i++)
                    {
                        angle += angleDelta;
                        path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
                    }

                    var startAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(startingAngle));
                    var endAngle   = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(endingAngle));
                    var steps      = Math.Max(1, (int)(Sides * MathHelper.Tau / Math.Abs(MathHelper.GetDeltaAngle(startAngle, endAngle)) + .5));
                    Mesh = VertexSourceToMesh.Revolve(path,
                                                      steps,
                                                      startAngle,
                                                      endAngle);
                }
            }

            if (valuesChanged)
            {
                Invalidate(InvalidateType.DisplayValues);
            }

            Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
            return(Task.CompletedTask);
        }
Esempio n. 24
0
        protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
        {
            if (windowService == null)
            {
                throw new ArgumentNullException("windowService");
            }

            if (objectProvider == null)
            {
                throw new ArgumentNullException("objectProvider");
            }

            if (objectProvider.GetObject() is List <List <IntPoint> > polygons)
            {
                var vertexStorage = PlatingHelper.PolygonToVertexStorage(polygons);

                var polygonsMesh = VertexSourceToMesh.Extrude(vertexStorage, zHeight: 30);

                // Position
                var aabb = polygonsMesh.GetAxisAlignedBoundingBox();
                polygonsMesh.Transform(Matrix4X4.CreateTranslation(-aabb.Center));
                polygonsMesh.Transform(Matrix4X4.CreateScale(1.6 / aabb.XSize));

                var systemWindow = new SystemWindow(800, 600);
                var lighting     = new LightingData();

                //Debugger.Launch();
                systemWindow.AfterDraw += (s, e) =>
                {
                    var screenSpaceBounds = systemWindow.TransformToScreenSpace(systemWindow.LocalBounds);

                    WorldView world = new WorldView(screenSpaceBounds.Width, screenSpaceBounds.Height);
                    //world.Translate(new Vector3(0, 0, 0));
                    //world.Rotate(Quaternion.FromEulerAngles(new Vector3(rotateX, 0, 0)));

                    GLHelper.SetGlContext(world, screenSpaceBounds, lighting);
                    GLHelper.Render(polygonsMesh, Color.White);
                    GLHelper.UnsetGlContext();
                };

                using (var displayForm = new OpenGLSystemWindow()
                {
                    AggSystemWindow = systemWindow
                })
                {
                    //System.Diagnostics.Debugger.Launch();
                    windowService.ShowDialog(displayForm);
                }
            }
        }
        private void Rebuild(UndoBuffer undoBuffer)
        {
            using (RebuildLock())
            {
                var vertexSource = this.VertexSource;
                Mesh = VertexSourceToMesh.Extrude(this.VertexSource, Height);
                if (Mesh.Vertices.Count == 0)
                {
                    Mesh = null;
                }
            }

            Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
        }
        public VertexStorageObject3D(VertexStorage vertexStorage)
        {
            this.vertexStorage = vertexStorage;

            this.Children.Modify(children =>
            {
                int i = 0;
                foreach (var v in vertexStorage.Vertices())
                {
                    if (!v.IsMoveTo && !v.IsLineTo)
                    {
                        continue;
                    }

                    var localVertex = v;

                    var localIndex = i++;

                    var item = new Object3D()
                    {
                        Mesh   = CreateCylinder(1, 1),
                        Matrix = Matrix4X4.CreateTranslation(v.position.X, v.position.Y, 0),
                        Color  = Color.Green
                    };

                    item.Invalidated += (s, e) =>
                    {
                        System.Diagnostics.Debugger.Break();
                        //vertexStorage.modify_vertex(localIndex, item.Matrix.Position.X, localVertex.position.Y = item.Matrix.Position.Y);
                    };

                    children.Add(item);
                }

                children.Add(generatedMesh = new Object3D()
                {
                    Mesh  = VertexSourceToMesh.Extrude(vertexStorage, 0.5),
                    Color = new Color("#93CEFF99")
                });
            });

            this.Invalidated += (s, e) =>
            {
                // Recompute path from content
                generatedMesh.Mesh = VertexSourceToMesh.Extrude(vertexStorage, 0.5);
                //VertexSourceToMesh.Revolve(vertexStorage));
            };
        }
Esempio n. 27
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");
            bool valuesChanged = false;

            double height        = Height.ClampIfNotCalculated(this, .01, 1000000, ref valuesChanged);
            var    diameter      = Diameter.ClampIfNotCalculated(this, .01, 1000000, ref valuesChanged);
            var    diameterTop   = DiameterTop.ClampIfNotCalculated(this, .01, 1000000, ref valuesChanged);
            var    sides         = Sides.ClampIfNotCalculated(this, 3, 360, ref valuesChanged);
            var    startingAngle = StartingAngle.ClampIfNotCalculated(this, 0, 360 - .01, ref valuesChanged);
            var    endingAngle   = EndingAngle.ClampIfNotCalculated(this, StartingAngle.Value(this) + .01, 360, ref valuesChanged);

            if (valuesChanged)
            {
                Invalidate(InvalidateType.DisplayValues);
            }

            using (RebuildLock())
            {
                using (new CenterAndHeightMaintainer(this))
                {
                    if (!Advanced)
                    {
                        var path = new VertexStorage();
                        path.MoveTo(0, -height / 2);
                        path.LineTo(diameter / 2, -height / 2);
                        path.LineTo(diameter / 2, height / 2);
                        path.LineTo(0, height / 2);

                        Mesh = VertexSourceToMesh.Revolve(path, sides);
                    }
                    else
                    {
                        var path = new VertexStorage();
                        path.MoveTo(0, -height / 2);
                        path.LineTo(diameter / 2, -height / 2);
                        path.LineTo(diameterTop / 2, height / 2);
                        path.LineTo(0, height / 2);

                        Mesh = VertexSourceToMesh.Revolve(path, sides, MathHelper.DegreesToRadians(startingAngle), MathHelper.DegreesToRadians(endingAngle));
                    }
                }
            }

            Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
            return(Task.CompletedTask);
        }
Esempio n. 28
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");
            bool valuesChanged = false;

            using (RebuildLock())
            {
                var latitudeSides  = LatitudeSides.ClampIfNotCalculated(this, 3, 180, ref valuesChanged);
                var longitudeSides = LongitudeSides.ClampIfNotCalculated(this, 3, 360, ref valuesChanged);
                var diameter       = Diameter.Value(this);

                using (new CenterAndHeightMaintainer(this))
                {
                    if (longitudeSides != lastLongitudeSides ||
                        latitudeSides != lastLatitudeSides ||
                        diameter != lastDiameter)
                    {
                        var radius     = diameter / 2;
                        var angleDelta = MathHelper.Tau / 4 / latitudeSides;
                        var angle      = 0.0;
                        var path       = new VertexStorage();
                        path.MoveTo(0, 0);
                        path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
                        for (int i = 0; i < latitudeSides; i++)
                        {
                            angle += angleDelta;
                            path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
                        }

                        Mesh = VertexSourceToMesh.Revolve(path, longitudeSides);
                    }

                    lastDiameter       = diameter;
                    lastLongitudeSides = longitudeSides;
                    lastLatitudeSides  = latitudeSides;
                }
            }

            if (valuesChanged)
            {
                Invalidate(InvalidateType.DisplayValues);
            }

            Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
            return(Task.CompletedTask);
        }
Esempio n. 29
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");
            bool valuesChanged = false;

            Sides         = agg_basics.Clamp(Sides, 3, 360, ref valuesChanged);
            Height        = agg_basics.Clamp(Height, .01, 1000000, ref valuesChanged);
            Diameter      = agg_basics.Clamp(Diameter, .01, 1000000, ref valuesChanged);
            StartingAngle = agg_basics.Clamp(StartingAngle, 0, 360 - .01, ref valuesChanged);
            EndingAngle   = agg_basics.Clamp(EndingAngle, StartingAngle + .01, 360, ref valuesChanged);

            if (valuesChanged)
            {
                Invalidate(InvalidateType.DisplayValues);
            }

            using (RebuildLock())
            {
                using (new CenterAndHeightMaintainer(this))
                {
                    if (!Advanced)
                    {
                        var path = new VertexStorage();
                        path.MoveTo(0, -Height / 2);
                        path.LineTo(Diameter / 2, -Height / 2);
                        path.LineTo(Diameter / 2, Height / 2);
                        path.LineTo(0, Height / 2);

                        Mesh = VertexSourceToMesh.Revolve(path, Sides);
                    }
                    else
                    {
                        var path = new VertexStorage();
                        path.MoveTo(0, -Height / 2);
                        path.LineTo(Diameter / 2, -Height / 2);
                        path.LineTo(DiameterTop / 2, Height / 2);
                        path.LineTo(0, Height / 2);

                        Mesh = VertexSourceToMesh.Revolve(path, Sides, MathHelper.DegreesToRadians(StartingAngle), MathHelper.DegreesToRadians(EndingAngle));
                    }
                }
            }

            Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
            return(Task.CompletedTask);
        }
Esempio n. 30
0
        private void Rebuild(UndoBuffer undoBuffer)
        {
            this.DebugDepth("Rebuild");
            bool changed = false;

            using (RebuildLock())
            {
                InnerDiameter = agg_basics.Clamp(InnerDiameter, 0, OuterDiameter - .1, ref changed);
                Sides         = agg_basics.Clamp(Sides, 3, 360, ref changed);

                var aabb = this.GetAxisAlignedBoundingBox();

                var startingAngle = StartingAngle;
                var endingAngle   = EndingAngle;
                if (!Advanced)
                {
                    startingAngle = 0;
                    endingAngle   = 360;
                }

                var innerDiameter = Math.Min(OuterDiameter - .1, InnerDiameter);

                var path = new VertexStorage();
                path.MoveTo(OuterDiameter / 2, -Height / 2);
                path.LineTo(OuterDiameter / 2, Height / 2);
                path.LineTo(innerDiameter / 2, Height / 2);
                path.LineTo(innerDiameter / 2, -Height / 2);
                path.LineTo(OuterDiameter / 2, -Height / 2);

                var startAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(startingAngle));
                var endAngle   = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(endingAngle));
                Mesh = VertexSourceToMesh.Revolve(path, Sides, startAngle, endAngle);

                if (aabb.ZSize > 0)
                {
                    // If the part was already created and at a height, maintain the height.
                    PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
                }
            }

            Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
            if (changed)
            {
                base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
            }
        }