public static CarveMesh PerformCSG(double[] firstVerts, int[] firstFaceIndices, int[] firstFaceSizes, double[] secondVerts, int[] secondFaceIndices, int[] secondFaceSizes, CSGOperations operation) { CarveMesh finalResult = null; unsafe { InteropMesh a = new InteropMesh(); InteropMesh b = new InteropMesh(); InteropMesh *result; fixed(double *aVerts = &firstVerts[0], bVerts = &secondVerts[0]) { fixed(int *aFaces = &firstFaceIndices[0], bFaces = &secondFaceIndices[0]) { fixed(int *aFSizes = &firstFaceSizes[0], bFSizes = &secondFaceSizes[0]) { a.numVertices = firstVerts.Length; a.numFaceIndices = firstFaceIndices.Length; a.vertices = aVerts; a.faceIndices = aFaces; a.faceSizes = aFSizes; a.numFaces = firstFaceSizes.Length; b.numVertices = secondVerts.Length; b.numFaceIndices = secondFaceIndices.Length; b.vertices = bVerts; b.faceIndices = bFaces; b.faceSizes = bFSizes; b.numFaces = secondFaceSizes.Length; try { result = performCSG(&a, &b, operation); } catch (SEHException ex) { ArgumentException e = new ArgumentException("Carve has thrown an error. Possible reason is corrupt or self-intersecting meshes", ex); throw e; } } } } if (result->numVertices == 0) { freeMesh(result); return(null); } finalResult = new CarveMesh(); finalResult.Vertices = new double[result->numVertices]; finalResult.FaceIndices = new int[result->numFaceIndices]; finalResult.FaceSizes = new int[result->numFaces]; if (result->numVertices > 0) { Parallel.For(0, finalResult.Vertices.Length, i => { finalResult.Vertices[i] = result->vertices[i]; }); } if (result->numFaceIndices > 0) { Parallel.For(0, finalResult.FaceIndices.Length, i => { finalResult.FaceIndices[i] = result->faceIndices[i]; }); } if (result->numFaces > 0) { Parallel.For(0, finalResult.FaceSizes.Length, i => { finalResult.FaceSizes[i] = result->faceSizes[i]; }); } freeMesh(result); } // end-unsafe return(finalResult); }
public static TetgenMesh Tetrahedralize(double[] vertList, int[] faceIndexList, int[] faceSizesList, TetgenBehaviour beh) { TetgenMesh finalResult = null; unsafe { InteropMesh a = new InteropMesh(); InteropMesh *result = null; fixed(double *aVerts = &vertList[0]) { fixed(int *aFaces = &faceIndexList[0]) { fixed(int *aFSizes = &faceSizesList[0]) { a.numVertices = vertList.Length / 3; a.numFaceIndices = faceIndexList.Length; a.vertices = aVerts; a.faceIndices = aFaces; a.faceSizes = aFSizes; a.numFaces = faceSizesList.Length; System.Console.WriteLine(string.Format("Num verts: {0}", a.numVertices)); System.Console.WriteLine(string.Format("Num face indices: {0}", a.numFaceIndices)); System.Console.WriteLine(string.Format("Num faces: {0}", a.numFaces)); TetgenBehaviourUnsafe bu = new TetgenBehaviourUnsafe(); bu.plc = beh.plc; bu.quality = beh.quality; bu.optlevel = beh.optlevel; bu.optmaxdihedral = beh.optmaxdihedral; bu.optminslidihed = beh.optminslidihed; bu.optminsmtdihed = beh.optminsmtdihed; bu.coarsen = beh.coarsen; bu.maxvolume = beh.maxvolume; bu.minratio = beh.minratio; bu.mindihedral = beh.mindihedral; bu.insertaddpoints = beh.insertaddpoints; bu.refine = beh.refine; bu.supsteiner_level = beh.supsteiner_level; //try //{ result = performTetgen(&a, &bu); //} //catch (SEHException ex) //{ // System.Console.WriteLine(ex.Message); // System.Console.WriteLine(ex.StackTrace); // System.Console.ReadLine(); //ArgumentException e = new ArgumentException("Tetgen has thrown an error. Possible reason is corrupt or self-intersecting meshes", ex); //throw e; //} } } } if (result == null) { System.Console.WriteLine("Result is null."); return(null); } if (result->numVertices == 0) { freeMesh(result); return(null); } finalResult = new TetgenMesh(); finalResult.Vertices = new double[result->numVertices * 3]; finalResult.FaceIndices = new int[result->numFaceIndices]; finalResult.FaceSizes = new int[result->numFaces]; finalResult.TetraIndices = new int[result->numTetra * 4]; finalResult.EdgeIndices = new int[result->numEdges * 2]; if (result->numVertices > 0) { Parallel.For(0, finalResult.Vertices.Length, i => { finalResult.Vertices[i] = result->vertices[i]; }); } if (result->numFaceIndices > 0) { Parallel.For(0, finalResult.FaceIndices.Length, i => { finalResult.FaceIndices[i] = result->faceIndices[i]; }); } if (result->numFaces > 0) { Parallel.For(0, finalResult.FaceSizes.Length, i => { finalResult.FaceSizes[i] = result->faceSizes[i]; }); } if (result->numTetra > 0) { Parallel.For(0, finalResult.TetraIndices.Length, i => { finalResult.TetraIndices[i] = result->tetra[i]; }); } if (result->numEdges > 0) { Parallel.For(0, finalResult.EdgeIndices.Length, i => { finalResult.EdgeIndices[i] = result->edges[i]; }); } //freeMesh(result); } // end-unsafe return(finalResult); }
private static unsafe extern InteropMesh *performCSG(ref InteropMesh a, ref InteropMesh b, CSGOperations op);
/// <summary> /// Performs the specified operation on the provided meshes. /// </summary> /// <param name="first">The first mesh</param> /// <param name="second">The second mesh</param> /// <param name="operation">The mesh opration to perform on the two meshes</param> /// <returns>A triangular mesh resulting from performing the specified operation. If the resulting mesh is empty, will return null.</returns> public static Mesh3 PerformCSG(Mesh3 first, Mesh3 second, CSGOperations operation) { Mesh3 finalResult = null; unsafe { InteropMesh a = new InteropMesh(); InteropMesh b = new InteropMesh(); Vector3[] aTransformed = first.GetTransformedVertices(); Vector3[] bTransformed = second.GetTransformedVertices(); InteropMesh *result; fixed(Vector3 *aVerts = &aTransformed[0], bVerts = &bTransformed[0]) { fixed(int *aTris = &first.TriangleIndices[0], bTris = &second.TriangleIndices[0]) { a.vertsArrayLength = first.Vertices.Length * 3; a.triArrayLength = first.TriangleIndices.Length; a.vertices = (double *)aVerts; a.triangleIndices = aTris; b.vertsArrayLength = second.Vertices.Length * 3; b.triArrayLength = second.TriangleIndices.Length; b.vertices = (double *)bVerts; b.triangleIndices = bTris; try { result = performCSG(ref a, ref b, operation); } catch (SEHException ex) { ArgumentException e = new ArgumentException("Carve has thrown an error. Possible reason is corrupt or self-intersecting meshes", ex); throw e; } } } if (result->vertsArrayLength == 0) { freeMesh(result); return(null); } Vector3[] vertices = new Vector3[result->vertsArrayLength / 3]; int[] triangleIndices = new int[result->triArrayLength]; // Copy the results back in parallel Parallel.For(0, vertices.Length, i => { vertices[i] = new Vector3(result->vertices[3 * i], result->vertices[3 * i + 1], result->vertices[3 * i + 2]); }); Parallel.For(0, triangleIndices.Length, i => { triangleIndices[i] = result->triangleIndices[i]; }); // If none of the vertices had colors, return whatever we have if (!first.HasColours && !second.HasColours) { finalResult = new Mesh3(vertices, triangleIndices); freeMesh(result); } else // Assign colors to the resulting mesh { uint[] colors = new uint[vertices.Length]; uint grayCode = 4286611584; // The uint value of the color gray (representing no color) // Assign the default gray to all vertices Parallel.For(0, colors.Length, i => { colors[i] = grayCode; }); #region Worst practices of parallel coding /** * The procedure for color matching is creating a map of (vertex=>color) and then * comparing all vertices of the resulting mesh (in parallel) with this map and * assigning colors as necessary */ if (first.HasColours) { ConcurrentDictionary <Vector3, uint> firstMap = new ConcurrentDictionary <Vector3, uint>(); // Create vertex to color map Parallel.For(0, aTransformed.Length, i => { firstMap[aTransformed[i]] = first.VertexColours[i]; }); // Assign colors Parallel.For(0, vertices.Length, i => { if (firstMap.ContainsKey(vertices[i])) { colors[i] = firstMap[vertices[i]]; } }); } if (second.HasColours) { ConcurrentDictionary <Vector3, uint> secondMap = new ConcurrentDictionary <Vector3, uint>(); Parallel.For(0, bTransformed.Length, i => { secondMap[bTransformed[i]] = second.VertexColours[i]; }); Parallel.For(0, vertices.Length, i => { if (secondMap.ContainsKey(vertices[i])) { colors[i] = secondMap[vertices[i]]; } }); } #endregion finalResult = new Mesh3(vertices, triangleIndices, colors); } } // end-unsafe Matrix3 transform = first.Transform.Invert(); finalResult = new Mesh3(finalResult.Vertices.Select(x => transform.Transform(x - first.Position)).ToArray(), finalResult.TriangleIndices, finalResult.VertexColours); finalResult.Position = first.Position; finalResult.Transform = first.Transform; return(finalResult); }
/// <summary> /// Performs the specified operation on the provided meshes. /// </summary> /// <param name="first">The first mesh</param> /// <param name="second">The second mesh</param> /// <param name="operation">The mesh opration to perform on the two meshes</param> /// <returns>A triangular mesh resulting from performing the specified operation. If the resulting mesh is empty, will return null.</returns> public static Tuple <int[], double[]> PerformCSG(int[] t1, int[] t2, double[] v1, double[] v2, CSGOperations operation) { Tuple <int[], double[]> finalResult = null; unsafe { InteropMesh a = new InteropMesh(); InteropMesh b = new InteropMesh(); InteropMesh *result; fixed(double *aVerts = &v1[0], bVerts = &v2[0]) { fixed(int *aTris = &t1[0], bTris = &t2[0]) { a.vertsArrayLength = v1.Length; a.triArrayLength = t1.Length; a.vertices = (double *)aVerts; a.triangleIndices = aTris; b.vertsArrayLength = v2.Length; b.triArrayLength = t2.Length; b.vertices = (double *)bVerts; b.triangleIndices = bTris; } } try { result = performCSG(ref a, ref b, operation); } catch (SEHException ex) { ArgumentException e = new ArgumentException("Carve has thrown an error. Possible reason is corrupt or self-intersecting meshes", ex); throw e; } if (result->vertsArrayLength == 0) { freeMesh(result); return(null); } double[] vertices = new double[result->vertsArrayLength]; int[] triangleIndices = new int[result->triArrayLength]; // Copy the results back in parallel for (int i = 0; i < vertices.Length; i++) { vertices[i] = result->vertices[i]; } for (int i = 0; i < triangleIndices.Length; i++) { triangleIndices[i] = result->triangleIndices[i]; } finalResult = Tuple.Create(triangleIndices, vertices); freeMesh(result); } // end-unsafe return(finalResult); }