public static CSG mesh2CSG(Mesh mesh) throws IOException { List<Polygon> polygons = new ArrayList<>(); List<Vector3d> vertices = new ArrayList<>(); if(mesh instanceof TriangleMesh){ // Get faces ObservableFaceArray faces = ((TriangleMesh)mesh).getFaces(); int[] f=new int[faces.size()]; faces.toArray(f); // Get vertices ObservableFloatArray points = ((TriangleMesh)mesh).getPoints(); float[] p = new float[points.size()]; points.toArray(p); // convert faces to polygons for(int i=0; i<faces.size()/6; i++){ int i0=f[6*i], i1=f[6*i+2], i2=f[6*i+4]; vertices.add(new Vector3d(p[3*i0], p[3*i0+1], p[3*i0+2])); vertices.add(new Vector3d(p[3*i1], p[3*i1+1], p[3*i1+2])); vertices.add(new Vector3d(p[3*i2], p[3*i2+1], p[3*i2+2])); polygons.add(Polygon.fromPoints(vertices)); vertices = new ArrayList<>(); } } return CSG.fromPolygons(new PropertyStorage(),polygons); }
private boolean checkPoints(ObservableFloatArray meshPoints) { return arraysEquals(points, meshPoints.toArray(new float[meshPoints.size()])); }
private boolean checkTexCoords(ObservableFloatArray tCoord) { return arraysEquals(tCoord.toArray(new float[tCoord.size()]), texCoords); }
public final ObservableFloatArray getPoints() { return mesh.getPoints(); }
public final ObservableFloatArray getTexCoords() { return mesh.getTexCoords(); }
private void optimizeFaces() { int total = 0, sameIndexes = 0, samePoints = 0, smallArea = 0; ObservableIntegerArray newFaces = FXCollections.observableIntegerArray(); ObservableIntegerArray newFaceSmoothingGroups = FXCollections.observableIntegerArray(); for (MeshView meshView : meshViews) { TriangleMesh mesh = (TriangleMesh) meshView.getMesh(); ObservableIntegerArray faces = mesh.getFaces(); ObservableIntegerArray faceSmoothingGroups = mesh.getFaceSmoothingGroups(); ObservableFloatArray points = mesh.getPoints(); newFaces.clear(); newFaces.ensureCapacity(faces.size()); newFaceSmoothingGroups.clear(); newFaceSmoothingGroups.ensureCapacity(faceSmoothingGroups.size()); int pointElementSize = mesh.getPointElementSize(); int faceElementSize = mesh.getFaceElementSize(); for (int i = 0; i < faces.size(); i += faceElementSize) { total++; int i1 = faces.get(i) * pointElementSize; int i2 = faces.get(i + 2) * pointElementSize; int i3 = faces.get(i + 4) * pointElementSize; if (i1 == i2 || i1 == i3 || i2 == i3) { sameIndexes++; continue; } Point3D p1 = new Point3D(points.get(i1), points.get(i1 + 1), points.get(i1 + 2)); Point3D p2 = new Point3D(points.get(i2), points.get(i2 + 1), points.get(i2 + 2)); Point3D p3 = new Point3D(points.get(i3), points.get(i3 + 1), points.get(i3 + 2)); if (p1.equals(p2) || p1.equals(p3) || p2.equals(p3)) { samePoints++; continue; } double a = p1.distance(p2); double b = p2.distance(p3); double c = p3.distance(p1); double p = (a + b + c) / 2; double sqarea = p * (p - a) * (p - b) * (p - c); final float DEAD_FACE = 1.f/1024/1024/1024/1024; // taken from MeshNormal code if (sqarea < DEAD_FACE) { smallArea++; // System.out.printf("a = %e, b = %e, c = %e, sqarea = %e\n" // + "p1 = %s\np2 = %s\np3 = %s\n", a, b, c, sqarea, p1.toString(), p2.toString(), p3.toString()); continue; } newFaces.addAll(faces, i, faceElementSize); int fIndex = i / faceElementSize; if (fIndex < faceSmoothingGroups.size()) { newFaceSmoothingGroups.addAll(faceSmoothingGroups.get(fIndex)); } } faces.setAll(newFaces); faceSmoothingGroups.setAll(newFaceSmoothingGroups); faces.trimToSize(); faceSmoothingGroups.trimToSize(); } int badTotal = sameIndexes + samePoints + smallArea; System.out.printf("Removed %d (%.2f%%) faces with same point indexes, " + "%d (%.2f%%) faces with same points, " + "%d (%.2f%%) faces with small area. " + "Total %d (%.2f%%) bad faces out of %d total.\n", sameIndexes, 100d * sameIndexes / total, samePoints, 100d * samePoints / total, smallArea, 100d * smallArea / total, badTotal, 100d * badTotal / total, total); }
private void optimizePoints() { int total = 0, duplicates = 0, check = 0; Map<Point3D, Integer> pp = new HashMap<>(); ObservableIntegerArray reindex = FXCollections.observableIntegerArray(); ObservableFloatArray newPoints = FXCollections.observableFloatArray(); for (MeshView meshView : meshViews) { TriangleMesh mesh = (TriangleMesh) meshView.getMesh(); ObservableFloatArray points = mesh.getPoints(); int pointElementSize = mesh.getPointElementSize(); int os = points.size() / pointElementSize; pp.clear(); newPoints.clear(); newPoints.ensureCapacity(points.size()); reindex.clear(); reindex.resize(os); for (int i = 0, oi = 0, ni = 0; i < points.size(); i += pointElementSize, oi++) { float x = points.get(i); float y = points.get(i + 1); float z = points.get(i + 2); Point3D p = new Point3D(x, y, z); Integer index = pp.get(p); if (index == null) { pp.put(p, ni); reindex.set(oi, ni); newPoints.addAll(x, y, z); ni++; } else { reindex.set(oi, index); } } int ns = newPoints.size() / pointElementSize; int d = os - ns; duplicates += d; total += os; points.setAll(newPoints); points.trimToSize(); ObservableIntegerArray faces = mesh.getFaces(); for (int i = 0; i < faces.size(); i += 2) { faces.set(i, reindex.get(faces.get(i))); } // System.out.printf("There are %d (%.2f%%) duplicate points out of %d total for mesh '%s'.\n", // d, 100d * d / os, os, meshView.getId()); check += mesh.getPoints().size() / pointElementSize; } System.out.printf("There are %d (%.2f%%) duplicate points out of %d total.\n", duplicates, 100d * duplicates / total, total); System.out.printf("Now we have %d points.\n", check); }
private void optimizeTexCoords() { int total = 0, duplicates = 0, check = 0; Map<Point2D, Integer> pp = new HashMap<>(); ObservableIntegerArray reindex = FXCollections.observableIntegerArray(); ObservableFloatArray newTexCoords = FXCollections.observableFloatArray(); for (MeshView meshView : meshViews) { TriangleMesh mesh = (TriangleMesh) meshView.getMesh(); ObservableFloatArray texcoords = mesh.getTexCoords(); int texcoordElementSize = mesh.getTexCoordElementSize(); int os = texcoords.size() / texcoordElementSize; pp.clear(); newTexCoords.clear(); newTexCoords.ensureCapacity(texcoords.size()); reindex.clear(); reindex.resize(os); for (int i = 0, oi = 0, ni = 0; i < texcoords.size(); i += texcoordElementSize, oi++) { float x = texcoords.get(i); float y = texcoords.get(i + 1); Point2D p = new Point2D(x, y); Integer index = pp.get(p); if (index == null) { pp.put(p, ni); reindex.set(oi, ni); newTexCoords.addAll(x, y); ni++; } else { reindex.set(oi, index); } } int ns = newTexCoords.size() / texcoordElementSize; int d = os - ns; duplicates += d; total += os; texcoords.setAll(newTexCoords); texcoords.trimToSize(); ObservableIntegerArray faces = mesh.getFaces(); for (int i = 1; i < faces.size(); i += 2) { faces.set(i, reindex.get(faces.get(i))); } // System.out.printf("There are %d (%.2f%%) duplicate texcoords out of %d total for mesh '%s'.\n", // d, 100d * d / os, os, meshView.getId()); check += mesh.getTexCoords().size() / texcoordElementSize; } System.out.printf("There are %d (%.2f%%) duplicate texcoords out of %d total.\n", duplicates, 100d * duplicates / total, total); System.out.printf("Now we have %d texcoords.\n", check); }
public ObservableFloatArray getPoints() { return points; }
public ObservableFloatArray getTexCoords() { return texCoords; }
public static void mesh2STL(String fileName, Mesh mesh) throws IOException{ if(!(mesh instanceof TriangleMesh)){ return; } // Get faces ObservableFaceArray faces = ((TriangleMesh)mesh).getFaces(); int[] f=new int[faces.size()]; faces.toArray(f); // Get vertices ObservableFloatArray points = ((TriangleMesh)mesh).getPoints(); float[] p = new float[points.size()]; points.toArray(p); StringBuilder sb = new StringBuilder(); sb.append("solid meshFX\n"); // convert faces to polygons for(int i=0; i<faces.size()/6; i++){ int i0=f[6*i], i1=f[6*i+2], i2=f[6*i+4]; Point3D pA=new Point3D(p[3*i0], p[3*i0+1], p[3*i0+2]); Point3D pB=new Point3D(p[3*i1], p[3*i1+1], p[3*i1+2]); Point3D pC=new Point3D(p[3*i2], p[3*i2+1], p[3*i2+2]); Point3D pN=pB.subtract(pA).crossProduct(pC.subtract(pA)).normalize(); sb.append(" facet normal ").append(pN.getX()).append(" ").append(pN.getY()).append(" ").append(pN.getZ()).append("\n"); sb.append(" outer loop\n"); sb.append(" vertex ").append(pA.getX()).append(" ").append(pA.getY()).append(" ").append(pA.getZ()).append("\n"); sb.append(" vertex ").append(pB.getX()).append(" ").append(pB.getY()).append(" ").append(pB.getZ()).append("\n"); sb.append(" vertex ").append(pC.getX()).append(" ").append(pC.getY()).append(" ").append(pC.getZ()).append("\n"); sb.append(" endloop\n"); sb.append(" endfacet\n"); } sb.append("endsolid meshFX\n"); // write file try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(fileName), Charset.forName("UTF-8"), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { writer.write(sb.toString()); } }