private void CreateRootModel()
        {
            bool show3DLine = false;

            switch (ObjectComboBox.SelectedIndex)
            {
            case 0:
                Ab3d.Meshes.SphereMesh3D sphere = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 80, 10);
                _rootMesh = sphere.Geometry;
                break;

            case 1:
                Ab3d.Meshes.SphereMesh3D sphere2 = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 80, 5);
                _rootMesh = sphere2.Geometry;
                break;

            case 2:
                // NOTE: Here we create an optimized version of sphere but it does not have texture coordinates
                // If we do not need texture coordinates (do not need to show texture), than we can slightly simplify the sphere model.
                // When we also need to create texture coordinates, the top most position that represent the same point in space is defined multiple times
                // - each time with slightly different texture coordinate (so that the whole top line on the texture is shown around the top sphere position).
                // Also there are x + 1 position around the sphere (in one row) - one additional position is added that the first and last position in the "row" are in the same space position,
                // but the first position has x texture coordinate 0, the last position has x texture coordinate 1 - this shows the whole texture nicely around the sphere.
                // If texture coordinates are not needed, than we do not need to define more than one upper and bottom positions,
                // and also do not need to add another position to the row.
                // Optimized sphere can be created only with SphereMesh3D object (not with SphereVisual3D)
                Ab3d.Meshes.SphereMesh3D sphere3 = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 80, 12, false);     // false: generateTextureCoordinates
                _rootMesh = sphere3.Geometry;
                break;

            case 3:
                Ab3d.Meshes.BoxMesh3D box = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(130, 60, 100), 1, 1, 1);
                _rootMesh = box.Geometry;
                break;

            case 4:
                Ab3d.Meshes.BoxMesh3D box2 = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(130, 60, 100), 4, 4, 4);
                _rootMesh = box2.Geometry;
                break;

            case 5:
                Ab3d.Meshes.CylinderMesh3D cylinder = new Ab3d.Meshes.CylinderMesh3D(new Point3D(0, -50, 0), 60, 100, 12, true);
                _rootMesh = cylinder.Geometry;
                break;

            case 6:
                Ab3d.Meshes.ConeMesh3D cone = new Ab3d.Meshes.ConeMesh3D(new Point3D(0, -50, 0), 30, 60, 100, 12, true);
                _rootMesh = cone.Geometry;
                break;

            case 7:
                Ab3d.Meshes.ConeMesh3D cone2 = new Ab3d.Meshes.ConeMesh3D(new Point3D(0, -50, 0), 30, 60, 100, 6, false);
                _rootMesh = cone2.Geometry;
                break;

            case 8:
                var readerObj   = new Ab3d.ReaderObj();
                var teapotModel = readerObj.ReadModel3D(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Resources\ObjFiles\Teapot.obj")) as GeometryModel3D;

                if (teapotModel == null)
                {
                    return;
                }

                // Get the teapot MeshGeometry3D
                _rootMesh = (MeshGeometry3D)teapotModel.Geometry;

                break;

            case 9:
                var line = new Ab3d.Visuals.LineVisual3D()
                {
                    StartPosition = new Point3D(0, 0, 0),
                    EndPosition   = new Point3D(100, 0, 0),
                    LineColor     = Colors.Silver,
                    LineThickness = 20
                };

                Show3DLines(line);
                show3DLine = true;
                break;

            case 10:
                var polyLineVisual3D = new Ab3d.Visuals.PolyLineVisual3D()
                {
                    Positions     = new Point3DCollection(new Point3D[] { new Point3D(-75, 50, 0), new Point3D(-25, 0, 0), new Point3D(25, 50, 0), new Point3D(75, 0, 0) }),
                    LineThickness = 20
                };

                Show3DLines(polyLineVisual3D);
                show3DLine = true;
                break;

            case 11:
                // This is the same line as in the previous sample (PolyLineVisual3D), but this time
                // it is created as diconnected list of lines - note that this requires that the positions are duplicated.
                var multiLineVisual3D = new Ab3d.Visuals.MultiLineVisual3D()
                {
                    Positions = new Point3DCollection(new Point3D[] { new Point3D(-75, 50, 0), new Point3D(-25, 0, 0),
                                                                      new Point3D(-25, 0, 0), new Point3D(25, 50, 0),
                                                                      new Point3D(25, 50, 0), new Point3D(75, 0, 0) }),
                    LineThickness = 20
                };

                Show3DLines(multiLineVisual3D);
                show3DLine = true;
                break;

            default:
                _rootMesh = null;
                break;
            }

            // If we were looking at 3D lines before and now we are looking an standard 3D models,
            // we adjust the camera back to the side view (from direct front view)
            if (_isShowing3DLines && !show3DLine)
            {
                Camera1.Heading  = 30;
                Camera1.Attitude = -20;
                Camera1.Distance = 300;
            }

            _isShowing3DLines = show3DLine;


            _rootModel          = new GeometryModel3D();
            _rootModel.Geometry = _rootMesh;
            _rootModel.Material = new DiffuseMaterial(Brushes.DarkBlue);

            ObjectModelVisual.Content = _rootModel;

            Ab3d.Utilities.ModelEventSource3D modelEventSource = new Ab3d.Utilities.ModelEventSource3D();
            modelEventSource.TargetModel3D = _rootModel;
            modelEventSource.MouseClick   += new Ab3d.Common.EventManager3D.MouseButton3DEventHandler(modelEventSource_MouseClick);

            _eventsManager.ResetEventSources3D();
            _eventsManager.RegisterEventSource3D(modelEventSource);

            MainViewport.Cursor = Cursors.Hand;
        }
Example #2
0
        private void CreateRootModel()
        {
            switch (ObjectComboBox.SelectedIndex)
            {
            case 0:
                Ab3d.Meshes.BoxMesh3D box = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(130, 60, 100), 1, 1, 1);
                _rootMesh = box.Geometry;
                break;

            case 1:
                Ab3d.Meshes.BoxMesh3D box2 = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(130, 60, 100), 4, 4, 4);
                _rootMesh = box2.Geometry;
                break;

            case 2:
                Ab3d.Meshes.SphereMesh3D sphere = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 80, 10);
                _rootMesh = sphere.Geometry;
                break;

            case 3:
                Ab3d.Meshes.SphereMesh3D sphere2 = new Ab3d.Meshes.SphereMesh3D(new Point3D(0, 0, 0), 80, 5);
                _rootMesh = sphere2.Geometry;
                break;

            case 4:
                Ab3d.Meshes.CylinderMesh3D cylinder = new Ab3d.Meshes.CylinderMesh3D(new Point3D(0, -50, 0), 60, 100, 12, true);
                _rootMesh = cylinder.Geometry;
                break;

            case 5:
                Ab3d.Meshes.ConeMesh3D cone = new Ab3d.Meshes.ConeMesh3D(new Point3D(0, -50, 0), 30, 60, 100, 12, true);
                _rootMesh = cone.Geometry;
                break;

            case 6:
                Ab3d.Meshes.ConeMesh3D cone2 = new Ab3d.Meshes.ConeMesh3D(new Point3D(0, -50, 0), 30, 60, 100, 6, false);
                _rootMesh = cone2.Geometry;
                break;

            case 7:
                var readerObj   = new Ab3d.ReaderObj();
                var teapotModel = readerObj.ReadModel3D(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Resources\ObjFiles\Teapot.obj")) as GeometryModel3D;

                if (teapotModel == null)
                {
                    return;
                }

                // Get the teapot MeshGeometry3D
                _rootMesh = (MeshGeometry3D)teapotModel.Geometry;

                break;

            default:
                _rootMesh = null;
                break;
            }


            var geometryModel3D = new GeometryModel3D(_rootMesh, new DiffuseMaterial(Brushes.Silver));

            MainViewport.Children.Clear();
            MainViewport.Children.Add(geometryModel3D.CreateModelVisual3D());

            MeshInspector.MeshGeometry3D = _rootMesh;
        }
        // See also:
        // - Objects3D/BooleanOperationsSample to see other boolean operations
        // - Utilities/TextureCoordinatesGeneratorSample to see other options to define TextureCoordinates that are needed to show texture images

        public ModelingWithBooleanOperations()
        {
            InitializeComponent();

            _orangeMaterial = new MaterialGroup();
            _orangeMaterial.Children.Add(new DiffuseMaterial(Brushes.Orange));
            _orangeMaterial.Children.Add(new SpecularMaterial(Brushes.White, 16));

            // We will start with a simple box
            // Create it manually with MeshGeometry3D
            MeshGeometry3D initialBoxMesh3D = new Ab3d.Meshes.BoxMesh3D(new Point3D(-100, 25, 0), new Size3D(200, 50, 100), 1, 1, 1).Geometry;

            // Without boolean operations, we could simply create the box with:
            //var boxVisual3D = new BoxVisual3D()
            //{
            //    CenterPosition = new Point3D(-100, 25, 0),
            //    Size = new Size3D(200, 50, 100),
            //    UseCachedMeshGeometry3D = false, // we should not use the cached
            //    Material = _orangeMaterial
            //};


            // Define MeshGeometry3D objects that will be used for subtractions
            var centerSphereMesh = new Ab3d.Meshes.SphereMesh3D(new Point3D(-100, 50, 0), 40, 16).Geometry;

            var box1Mesh = new Ab3d.Meshes.BoxMesh3D(new Point3D(-180, 0, -30), new Size3D(10, 200, 10), 1, 1, 1).Geometry;
            var box2Mesh = new Ab3d.Meshes.BoxMesh3D(new Point3D(-180, 0, 0), new Size3D(10, 200, 10), 1, 1, 1).Geometry;
            var box3Mesh = new Ab3d.Meshes.BoxMesh3D(new Point3D(-180, 0, 30), new Size3D(10, 200, 10), 1, 1, 1).Geometry;

            var cylinder1Mesh3D = new Ab3d.Meshes.CylinderMesh3D(new Point3D(-20, 0, -30), 8, 200, segments: 16, isSmooth: false).Geometry;
            var cylinder2Mesh3D = new Ab3d.Meshes.CylinderMesh3D(new Point3D(-20, 0, 0), 8, 200, segments: 16, isSmooth: false).Geometry;
            var cylinder3Mesh3D = new Ab3d.Meshes.CylinderMesh3D(new Point3D(-20, 0, 30), 8, 200, segments: 16, isSmooth: false).Geometry;


            // When doing multiple boolean operations one after another,
            // it is recommended (and mush faster) to use BooleanMesh3D object.

            var booleanMesh3D = new Ab3d.Meshes.BooleanMesh3D(initialBoxMesh3D);

            booleanMesh3D.Subtract(centerSphereMesh);

            booleanMesh3D.Subtract(box1Mesh);
            booleanMesh3D.Subtract(box2Mesh);
            booleanMesh3D.Subtract(box3Mesh);

            booleanMesh3D.Subtract(cylinder1Mesh3D);
            booleanMesh3D.Subtract(cylinder2Mesh3D);
            booleanMesh3D.Subtract(cylinder3Mesh3D);


            // It is also possible to use Subtract method on BoxVisual3D object:
            //boxVisual3D.Subtract(centerSphereMesh);
            //boxVisual3D.Subtract(box1Mesh);
            //boxVisual3D.Subtract(box2Mesh);
            //boxVisual3D.Subtract(box3Mesh);
            //boxVisual3D.Subtract(cylinder1Mesh3D);
            //boxVisual3D.Subtract(cylinder2Mesh3D);
            //boxVisual3D.Subtract(cylinder3Mesh3D);


            // We could also use the static methods on Ab3d.Utilities.MeshBooleanOperations class:
            //Ab3d.Utilities.MeshBooleanOperations.Subtract(boxVisual3D, sphereMesh);
            //Ab3d.Utilities.MeshBooleanOperations.Subtract(boxVisual3D, boxMesh);


            // When calling the Geometry getter, the BooleanMesh3D converts the internal object into MeshGeometry3D.
            var meshGeometry3D = booleanMesh3D.Geometry;

            var initialGeometryModel3D = new GeometryModel3D(meshGeometry3D, _orangeMaterial);
            var boxVisual3D            = initialGeometryModel3D.CreateModelVisual3D();

            // Now add the changed box to the scene
            MainViewport.Children.Add(boxVisual3D);



            // When working with more complex meshes, the boolean operations can take some time.
            // To prevent blocking UI thread, we can do the boolean operations in the background thread.
            // To do this we need to freeze the MeshGeometry3D that are send to the background thread and back to UI thread.
            //
            // The following code is using spheres with 30 segments to demonstrate a longer boolean operations.
            //

            // First define the original MeshGeometry3D
            initialBoxMesh3D = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 25, 0), new Size3D(100, 50, 100), 1, 1, 1).Geometry;

            ShowNewOriginalMesh(initialBoxMesh3D);


            var initialBooleanMesh3D = new Ab3d.Meshes.BooleanMesh3D(initialBoxMesh3D);

            var sphereCenters = new Point3D[]
            {
                new Point3D(-50, 50, 50),
                new Point3D(50, 50, 50),
                new Point3D(50, 50, -50),
                new Point3D(-50, 50, -50),
                new Point3D(-50, 0, 50),
                new Point3D(50, 0, 50),
                new Point3D(50, 0, -50),
                new Point3D(-50, 0, -50)
            };

            // We can create the MeshGeometry3D and prepare the BooleanMesh3D in parallel - each can be created in its own thread
            var sphereBooleanMeshes = sphereCenters.AsParallel().Select(sphereCenter =>
            {
                //System.Diagnostics.Debug.WriteLine($"Start creating SphereMesh3D with {sphereCenter} on {System.Threading.Thread.CurrentThread.ManagedThreadId}");

                var sphereMeshGeometry3D = new Ab3d.Meshes.SphereMesh3D(sphereCenter, radius: 15, segments: 30).Geometry;
                var sphereBooleanMesh3D  = new Ab3d.Meshes.BooleanMesh3D(sphereMeshGeometry3D);

                return(sphereBooleanMesh3D);
            });

            // After that we can subtract each of the sphere meshes from the initialBooleanMesh3D.
            // This can be done in background thread (we use Dispatcher.Invoke to "send" the mesh to the UI thread)
            Task.Factory.StartNew(() =>
            {
                // Note the order in which the sphereBooleanMesh are created is not determined (as the BooleanMesh3D are created, they get available to the foreach)
                foreach (var sphereBooleanMesh in sphereBooleanMeshes)
                {
                    // Subtract the sphereBooleanMesh from the initialBooleanMesh3D
                    initialBooleanMesh3D.Subtract(sphereBooleanMesh);

                    // Get the MeshGeometry3D
                    var mesh = initialBooleanMesh3D.Geometry;

                    // Freeze the MeshGeometry3D
                    // This will allow using the mesh in UI thread (different thread as the mesh was created)
                    mesh.Freeze();

                    // Send it to UI thread
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        ShowNewOriginalMesh(mesh);
                    }));
                }
            })
            // After all the boolean operations are completed, we generate texture coordinates
            // so we will be able to use texture image as material (meshes that are created with boolean operations do not have texture coordinates defined)
            .ContinueWith(_ => GenerateTextureCoordinates(), TaskScheduler.FromCurrentSynchronizationContext()); // The last one is run on UI thread
        }