//Для выполнения операции выделить 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); }
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(); }