private Matrix4X4 GetCenteringTransformVisualCenter(IEnumerable <IObject3D> items, double goalRadius)
        {
            IEnumerable <(Vector2, Vector2, Vector2)> GetPolygons()
            {
                foreach (var item in items)
                {
                    foreach (var meshItem in item.VisibleMeshes())
                    {
                        var worldMatrix = meshItem.WorldMatrix(this);
                        var faces       = meshItem.Mesh.Faces;
                        var vertices    = meshItem.Mesh.Vertices;
                        foreach (var face in faces)
                        {
                            if (face.normal.TransformNormal(worldMatrix).Z > 0)
                            {
                                yield return(
                                    new Vector2(vertices[face.v0].Transform(worldMatrix)),
                                    new Vector2(vertices[face.v1].Transform(worldMatrix)),
                                    new Vector2(vertices[face.v2].Transform(worldMatrix))
                                    );
                            }
                        }
                    }
                }
            }

            var outsidePolygons = new List <List <IntPoint> >();

            var projection = new Polygons();

            // remove all holes from the polygons so we only center the major outlines
            var polygons = OrthographicZProjection.GetClipperPolygons(GetPolygons());

            foreach (var polygon in polygons)
            {
                if (polygon.GetWindingDirection() == 1)
                {
                    outsidePolygons.Add(polygon);
                }
            }

            IVertexSource outsideSource = outsidePolygons.CreateVertexStorage();

            Vector2 center = outsideSource.GetWeightedCenter();

            outsideSource = new VertexSourceApplyTransform(outsideSource, Affine.NewTranslation(-center));

            double radius = MaxXyDistFromCenter(outsideSource);

            double scale    = goalRadius / radius;
            var    scalling = Matrix4X4.CreateScale(scale, scale, 1);

            var centering = Matrix4X4.CreateTranslation(-center.X, -center.Y, 0);

            return(centering * scalling);
        }
        private void LoadStl_Click(object sender, EventArgs e)
        {
            OpenFileDialogParams opeParams = new OpenFileDialogParams("STL Files|*.stl");

            FileDialog.OpenFileDialog(opeParams, (openParams) =>
            {
                var streamToLoadFrom = File.Open(openParams.FileName, FileMode.Open);

                if (streamToLoadFrom != null)
                {
                    var loadedFileName = openParams.FileName;

                    meshToRender = StlProcessing.Load(streamToLoadFrom);

                    ImageBuffer plateInventory = new ImageBuffer((int)(300 * 8.5), 300 * 11, 32, new BlenderBGRA());
                    Graphics2D plateGraphics   = plateInventory.NewGraphics2D();
                    plateGraphics.Clear(RGBA_Bytes.White);

                    double inchesPerMm          = 0.0393701;
                    double pixelsPerInch        = 300;
                    double pixelsPerMm          = inchesPerMm * pixelsPerInch;
                    AxisAlignedBoundingBox aabb = meshToRender.GetAxisAlignedBoundingBox();
                    Vector2 lowerLeftInMM       = new Vector2(-aabb.minXYZ.x, -aabb.minXYZ.y);
                    Vector3 centerInMM          = (aabb.maxXYZ - aabb.minXYZ) / 2;
                    Vector2 offsetInMM          = new Vector2(20, 30);

                    {
                        RectangleDouble bounds = new RectangleDouble(offsetInMM.x * pixelsPerMm,
                                                                     offsetInMM.y * pixelsPerMm,
                                                                     (offsetInMM.x + aabb.maxXYZ.x - aabb.minXYZ.x) * pixelsPerMm,
                                                                     (offsetInMM.y + aabb.maxXYZ.y - aabb.minXYZ.y) * pixelsPerMm);
                        bounds.Inflate(3 * pixelsPerMm);
                        RoundedRect rect = new RoundedRect(bounds, 3 * pixelsPerMm);
                        plateGraphics.Render(rect, RGBA_Bytes.LightGray);
                        Stroke rectOutline = new Stroke(rect, .5 * pixelsPerMm);
                        plateGraphics.Render(rectOutline, RGBA_Bytes.DarkGray);
                    }

                    OrthographicZProjection.DrawTo(plateGraphics, meshToRender, lowerLeftInMM + offsetInMM, pixelsPerMm);
                    plateGraphics.DrawString(Path.GetFileName(openParams.FileName), (offsetInMM.x + centerInMM.x) * pixelsPerMm, (offsetInMM.y - 10) * pixelsPerMm, 50, Agg.Font.Justification.Center);

                    //ImageBuffer logoImage = new ImageBuffer();
                    //ImageIO.LoadImageData("Logo.png", logoImage);
                    //plateGraphics.Render(logoImage, (plateInventory.Width - logoImage.Width) / 2, plateInventory.Height - logoImage.Height - 10 * pixelsPerMm);

                    //ImageIO.SaveImageData("plate Inventory.jpeg", plateInventory);
                }
            });
        }