Example #1
0
        //Для выполнения операции выделить 2 MeshInSpace. Результат будет помещен в первый MeshInSpace. Если операция Union то в первом MeshInSpace объединятся все geometry.
        //Для операций Intersect,Subtract, geometry из первого MeshInSpace обрабатываются раздельно.
        //На основе библиотеки Net3dBool. Эта библиотека после действия возвращает массив Vector3[] positions, int[] indices. Данные о Structure теряются.
        //Потом автоматически строится простая Structure, расчитываются нормали.

        //BoolActionEnum.Union - Implements constructive solid geometry union operation for two selected Mesh In Space objects:
        //BoolActionEnum.Subtruct - Implements constructive solid geometry difference operation for two selected Mesh In Space objects.
        //                          The result object will be the first selected mesh minus the second selected mesh.
        //BoolActionEnum.Intersect - Implements constructive solid geometry intersect operation for two selected Mesh In Space objects.
        public static void BoolAction(ActionContext actionContext, BoolActionEnum boolAction)
        {
            if (actionContext.SelectionMode != SelectionMode.Object)
            {
                return;
            }

            void Exec(Component_MeshInSpace[] selectedMeshInSpaces, UndoMultiAction undoForMeshes, UndoMultiAction undoForOtherActions)
            {
                if (selectedMeshInSpaces.Length != 2)
                {
                    return;
                }

                BoolActionExecute(selectedMeshInSpaces[0], selectedMeshInSpaces[1], undoForMeshes, actionContext.DocumentWindow?.Document, boolAction);
            }

            ExecuteAction(actionContext, Exec);
        }
Example #2
0
        public static void BoolActionExecute(Component_MeshInSpace firstMeshInSpace, Component_MeshInSpace secondMeshInSpace, UndoMultiAction undo, DocumentInstance document, BoolActionEnum boolAction)
        {
            //the first operand of the union operation must be a single geometry, otherwise duplicate parts will be made.
            if (boolAction == BoolActionEnum.Union && 1 < firstMeshInSpace.Mesh.Value.GetComponents <Component_MeshGeometry>().Length)
            {
                MergeGeometries(firstMeshInSpace.Mesh, document, undo);
            }
            bool needUndoForNextActions = true;

            CommonFunctions.ConvertProceduralMeshGeometries(document, firstMeshInSpace.Mesh, undo, ref needUndoForNextActions);

            List <(Vector3F[] positions, int[] indices)> data1List = GetData(firstMeshInSpace);

            (Vector3F[] positions, int[] indices)data2 = MergeData(GetData(secondMeshInSpace));

            //convert the second mesh in space, to the transform of first mesh in space
            var matrix = firstMeshInSpace.Transform.Value.ToMatrix4().GetInverse() * secondMeshInSpace.Transform.Value.ToMatrix4();

            Net3dBool.Vector3[] vertices2 = new Net3dBool.Vector3[data2.positions.Length];
            for (int i = 0; i < data2.positions.Length; i++)
            {
                vertices2[i] = ToNet3DBoolVector3((matrix * data2.positions[i]).ToVector3F());
            }
            var operand2 = new Net3dBool.Solid(vertices2, data2.indices);

            var geometries         = firstMeshInSpace.Mesh.Value.GetComponents <Component_MeshGeometry>();
            var resultGeometries   = new List <(Vector3F[] positions, int[] indices, MeshData.MeshGeometryFormat format)>();
            var geometriesToDelete = new List <Component_MeshGeometry>();

            for (int geomIndex = 0; geomIndex < data1List.Count; geomIndex++)
            {
                var data1 = data1List[geomIndex];
                Net3dBool.Vector3[] vertices1 = data1.positions.Select(ToNet3DBoolVector3).ToArray();

                var modeller = new Net3dBool.BooleanModeller(new Net3dBool.Solid(vertices1, data1.indices), operand2);                     //Большую часть времени на вычисления занимает эта сторка

                Net3dBool.Solid result = null;
                switch (boolAction)
                {
                case BoolActionEnum.Union: result = modeller.GetUnion(); break;

                case BoolActionEnum.Intersect: result = modeller.GetIntersection(); break;

                case BoolActionEnum.Subtract: result = modeller.GetDifference(); break;

                default: return;
                }

                var newVertices = result.getVertices().Select(ToVector3F).ToArray();
                if (0 < newVertices.Length)
                {
                    resultGeometries.Add((newVertices, result.getIndices(), new MeshData.MeshGeometryFormat(geometries[geomIndex].VertexStructure)));
                }
                else
                {
                    geometriesToDelete.Add(geometries[geomIndex]);
                }
            }

            foreach (var g in resultGeometries)
            {
                if (!CheckValid(g.positions, g.indices))
                {
                    throw new Exception();
                }
            }

            //delete empty mesh geometry //
            if (0 < geometriesToDelete.Count)
            {
                undo?.AddAction(new UndoActionComponentCreateDelete(document, geometriesToDelete.ToArray(), create: false));
            }

            var meshData = MeshData.BuildFromRaw(resultGeometries);

            meshData?.Save(firstMeshInSpace.Mesh.Value, needUndoForNextActions ? undo : null, null);               //??? No selection?
            firstMeshInSpace.Mesh.Value?.RebuildStructure();
        }