private int getMiddle(int v1, Point2D p1, int v2, Point2D p2) { String key = "" + Math.min(v1, v2) + "_" + Math.max(v1, v2); if (map.get(key) != null) { return map.get(key); } texCoord1.add(p1.add(p2).multiply(0.5f)); map.put(key, index.get()); return index.getAndIncrement(); }
private TriangleMesh createTetrahedra(float height, int level) { TriangleMesh m0 = null; if (level > 0) { m0 = createTetrahedra(height, level - 1); } if (level == 0) { a = new Affine(); float hw = height; if (center.get() != null) { a = a.createConcatenation(new Translate(center.get().x, center.get().y, center.get().z)); } final float[] baseVertices = new float[] { 0f, 0f, 0.612372f * hw, -0.288675f * hw, -0.5f * hw, -0.204124f * hw, -0.288675f * hw, 0.5f * hw, -0.204124f * hw, 0.57735f * hw, 0f, -0.204124f * hw }; final float[] baseTexCoords = new float[] { 0f, 0f, 0.5f, 0.866025f, 1f, 0f, 1f, 1.73205f, 1.5f, 0.866025f, 2f, 0f }; final int[] baseTexture = new int[] { 0, 2, 1, 3, 1, 4, 2, 4, 1, 4, 2, 5 }; final List<Integer> baseFaces = Arrays.asList(1, 2, 3, 2, 1, 0, 3, 0, 1, 0, 3, 2); for (int i = 0; i < baseVertices.length / 3; i++) { Point3D ta = transform(baseVertices[3 * i], baseVertices[3 * i + 1], baseVertices[3 * i + 2]); baseVertices[3 * i] = ta.x; baseVertices[3 * i + 1] = ta.y; baseVertices[3 * i + 2] = ta.z; } points0 = baseVertices; numVertices = baseVertices.length / 3; texCoord0 = baseTexCoords; numTexCoords = baseTexCoords.length / 2; faces0 = IntStreams.range(0, baseFaces.size() / 3) .mapToObj( i -> IntStreams.of( baseFaces.get(3 * i), baseTexture[3 * i], baseFaces.get(3 * i + 1), baseTexture[3 * i + 1], baseFaces.get(3 * i + 2), baseTexture[3 * i + 2])) .flatMapToInt(i -> i) .toArray(); numFaces = baseFaces.size() / 3; } else if (m0 != null) { points0 = new float[numVertices * m0.getPointElementSize()]; m0.getPoints().toArray(points0); } List<Point3D> points1 = IntStreams.range(0, numVertices) .mapToObj(i -> new Point3D(points0[3 * i], points0[3 * i + 1], points0[3 * i + 2])) .collect(Collectors.toList()); if (level > 0 && m0 != null) { texCoord0 = new float[numTexCoords * m0.getTexCoordElementSize()]; m0.getTexCoords().toArray(texCoord0); } texCoord1 = IntStreams.range(0, numTexCoords) .mapToObj(i -> new Point2D(texCoord0[2 * i], texCoord0[2 * i + 1])) .collect(Collectors.toList()); if (level > 0 && m0 != null) { faces0 = new int[numFaces * m0.getFaceElementSize()]; m0.getFaces().toArray(faces0); } List<Face3> faces1 = IntStreams.range(0, numFaces) .mapToObj(i -> new Face3(faces0[6 * i], faces0[6 * i + 2], faces0[6 * i + 4])) .collect(Collectors.toList()); index.set(points1.size()); map.clear(); listVertices.clear(); listFaces.clear(); listVertices.addAll(points1); Iterables.forEach( faces1, face -> { int v1 = face.p0; int v2 = face.p1; int v3 = face.p2; if (level > 0) { int a = getMiddle(v1, points1.get(v1), v2, points1.get(v2)); int b = getMiddle(v2, points1.get(v2), v3, points1.get(v3)); int c = getMiddle(v3, points1.get(v3), v1, points1.get(v1)); listFaces.add(new Face3(v1, a, c)); listFaces.add(new Face3(v2, b, a)); listFaces.add(new Face3(v3, c, b)); listFaces.add(new Face3(a, b, c)); } else { listFaces.add(new Face3(v1, v2, v3)); } }); map.clear(); numVertices = listVertices.size(); numFaces = listFaces.size(); List<Face3> textures1; if (level == 0) { textures1 = IntStreams.range(0, faces0.length / 6) .mapToObj(i -> new Face3(faces0[6 * i + 1], faces0[6 * i + 3], faces0[6 * i + 5])) .collect(Collectors.toList()); } else { textures1 = stream(listTextures).map(t -> t).collect(Collectors.toList()); } index.set(texCoord1.size()); listTextures.clear(); Iterables.forEach( textures1, face -> { int v1 = face.p0; int v2 = face.p1; int v3 = face.p2; if (level > 0) { int a = getMiddle(v1, texCoord1.get(v1), v2, texCoord1.get(v2)); int b = getMiddle(v2, texCoord1.get(v2), v3, texCoord1.get(v3)); int c = getMiddle(v3, texCoord1.get(v3), v1, texCoord1.get(v1)); listTextures.add(new Face3(v1, a, c)); listTextures.add(new Face3(v2, b, a)); listTextures.add(new Face3(v3, c, b)); listTextures.add(new Face3(a, b, c)); } else { listTextures.add(new Face3(v1, v2, v3)); } }); map.clear(); texCoord0 = stream(texCoord1) .flatMapToDouble(p -> DoubleStreams.of(p.getX(), p.getY())) .collect( () -> new FloatCollector(texCoord1.size() * 2), FloatCollector::add, FloatCollector::join) .toArray(); numTexCoords = texCoord0.length / 2; textureCoords = texCoord0; if (level == getLevel()) { areaMesh.setWidth(2f * height); areaMesh.setHeight(height * Math.sqrt(3)); // 1<<j -> bitset, 00100. Otherwise: 000111 will mean they are shared smoothingGroups = IntStreams.range(0, listFaces.size()) .map(i -> 1 << (i / (listFaces.size() / 4))) .toArray(); // smoothing groups based on 3DViewer -> same result // float[] normals=new float[]{1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1}; // int[] newFaces = IntStreams.range(0, listFaces.size()) // .mapToObj(i->IntStream.of((int)listFaces.get(i).x, // (int)listFaces.get(i).x, // (int)listFaces.get(i).y, (int)listFaces.get(i).y, // (int)listFaces.get(i).z, (int)listFaces.get(i).z)) // .flatMapToInt(i->i).toArray(); // int[] newFaceNormals = IntStreams.range(0,listFaces.size()).mapToObj(i->{ // int j=(i/(listFaces.size()/6)); // return IntStream.of(j,j,j); // }).flatMapToInt(i->i).toArray(); // smoothingGroups=SmoothingGroups.calcSmoothGroups(new TriangleMesh(), newFaces, // newFaceNormals, normals); } return createMesh(); }