/* * Copyright (c) 2005–2012 Goethe Center for Scientific Computing - Simulation and Modelling (G-CSC Frankfurt) * Copyright (c) 2012-2015 Goethe Center for Scientific Computing - Computational Neuroscience (G-CSC Frankfurt) * * This file is part of NeuGen. * * NeuGen is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * as published by the Free Software Foundation. * * see: http://opensource.org/licenses/LGPL-3.0 * file://path/to/NeuGen/LICENSE * * NeuGen is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * This version of NeuGen includes copyright notice and attribution requirements. * According to the LGPL this information must be displayed even if you modify * the source code of NeuGen. The copyright statement/attribution may not be removed. * * Attribution Requirements: * * If you create derived work you must do the following regarding copyright * notice and author attribution. * * Add an additional notice, stating that you modified NeuGen. In addition * you must cite the publications listed below. A suitable notice might read * "NeuGen source code modified by YourName 2012". * * Note, that these requirements are in full accordance with the LGPL v3 * (see 7. Additional Terms, b). * * Publications: * * S. Wolf, S. Grein, G. Queisser. NeuGen 2.0 - * Employing NeuGen 2.0 to automatically generate realistic * morphologies of hippocapal neurons and neural networks in 3D. * Neuroinformatics, 2013, 11(2), pp. 137-148, doi: 10.1007/s12021-012-9170-1 * * * J. P. Eberhard, A. Wanner, G. Wittum. NeuGen - * A tool for the generation of realistic morphology * of cortical neurons and neural networks in 3D. * Neurocomputing, 70(1-3), pp. 327-343, doi: 10.1016/j.neucom.2006.01.028 * */ /* * Util.java * * Created on 17. Februar 2007 * * Another idea for the visualization of iso-surfaces is the marching cube idea. * This is a very straight forward implementation of a surface triangulation of a cloud * of points in 3D in Java. ( the inner points of the object are not considered ) * * The input data is a 3d array of float values (float[ ][ ][ ] data). * The algorithm for the surface triangulation involves three basic steps: * * - find all boundary points in the data set * - find all neighbouring boundary points for each boundary point * - find three neighbouring boundary points and assign them to a new triangle. * It obtains a list of triangles. * * * * // //dimensions of volume of voxels * // int VOV_L = this.volumeOfVoxels.getNumberOfVoxelsX(); * // int VOV_W = this.volumeOfVoxels.getNumberOfVoxelsY(); * // int VOV_H = this.volumeOfVoxels.getNumberOfVoxelsZ(); * // // test of visualization with sphere * // VolumeOfVoxels vv1 = new VolumeOfVoxels(10, 10, 10); * // vv1.fillVolumeOfSphere(false); * // // Simple visualization by triangles * // Vector<Triangle> triangleVector = new Vector<Triangle>(); * // Util.triangulation(this.vv.getVoxelsValueAsFloatArray(), * // VOV_L, VOV_W, VOV_H, triangleVector); * // Triangle3dCreator triangleCreator = new * // Triangle3dCreator(ColorUtil.grey); * // for (Triangle t : triangleVector) { * // triangleCreator.addTriangleToContainer((t.getP1AsScaledPoint3f(1.0f * // / * // VOV_L, 1.0f / VOV_W, 1.0f / VOV_H)), * // (t.getP2AsScaledPoint3f(1.0f / VOV_L, 1.0f / VOV_W, 1.0f / * // VOV_H)), (t .getP3AsScaledPoint3f(1.0f / VOV_L, 1.0f / VOV_W, * // 1.0f / VOV_H))); * // t.printData(); * // } * // contentRoot.addChild(triangleCreator.getTriangleContainer()); * * * */ package org.neugen.simpletriangulation; import java.util.Vector; /** * A util class of useful functions for three dimensions * * @author Jens Eberhard */ public class Util { /** Creates a new instance of Util */ public Util() { } /** * Checks if the voxel at (x,y,z) in dataset d is background ( P(x,y,z) < * threshold ) treshold is e.g. 0.05 */ public static boolean isBackground(float[][][] d, int x, int y, int z) { try { return (d[x][y][z] < 0.05); } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); } return false; } /** * Checks if the voxel at (x,y,z) in dataset d is a boundary voxel * * P(x,y,z) is boundary <- : - P(x,y,z) != background && - at least one * neighbour is background */ public static boolean isBoundary(float[][][] d, int x, int y, int z) { if (isBackground(d, x, y, z)) { return false; } try { return (isBackground(d, x - 1, y - 1, z - 1) || isBackground(d, x - 1, y - 1, z) || isBackground(d, x - 1, y - 1, z + 1) || isBackground(d, x - 1, y, z - 1) || isBackground(d, x - 1, y, z) || isBackground(d, x - 1, y, z + 1) || isBackground(d, x - 1, y + 1, z - 1) || isBackground(d, x - 1, y + 1, z) || isBackground(d, x - 1, y + 1, z + 1) || isBackground(d, x, y - 1, z - 1) || isBackground(d, x, y - 1, z) || isBackground(d, x, y - 1, z + 1) || isBackground(d, x, y, z - 1) || isBackground(d, x, y, z + 1) || isBackground(d, x, y + 1, z - 1) || isBackground(d, x, y + 1, z) || isBackground(d, x, y + 1, z + 1) || isBackground(d, x + 1, y - 1, z - 1) || isBackground(d, x + 1, y - 1, z) || isBackground(d, x + 1, y - 1, z + 1) || isBackground(d, x + 1, y, z - 1) || isBackground(d, x + 1, y, z) || isBackground(d, x + 1, y, z + 1) || isBackground(d, x + 1, y + 1, z - 1) || isBackground(d, x + 1, y + 1, z) || isBackground(d, x + 1, y + 1, z + 1)); } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); return false; } } /** * triangulation of the surfaces given in the dataset data - find all * boundary points in the dataset - determine for each boundary point p1 * all neighbouring boundary points - check if one of the neighbouring * boundary points of p1 has a neighbouring boundary point which is a * neighbour of p1, too -> save the found triangle */ @SuppressWarnings({"unused", "cast"}) public static void triangulation(float[][][] data, int width, int height, int depth, Vector<Triangle> t) { int x, y, z; System.out.println("Triangulation into triangles started..."); // a vector to save all boundary points found in data Vector<Point3D> boundaryPoints = new Vector<Point3D>(0); for (z = 1; z < depth - 1; z++) { for (y = 1; y < height - 1; y++) { for (x = 1; x < width - 1; x++) { if (Util.isBoundary(data, x, y, z)) { boundaryPoints.add(new Point3D(x, y, z)); } } } } if (t.size() > 0) { t.clear(); } // neighbours_vector is a vector wich should // hold a vector off all neighbour points // -> all neighbours of the fifth point // in the points vector will be stored in // a vector at the 5th position in the // neighbours_vector // (n.b.: only points wich are at a later position // in the points vector to avoid redundancy ) Vector<Vector<Point3D>> neighbours_vector = new Vector<Vector<Point3D>>(boundaryPoints.size()); Vector<Point3D> neighbours; Point3D p1, p2, p3; // create list of neighbours for each point for (int i = 0; i < boundaryPoints.size(); i++) { neighbours = new Vector<Point3D>(0); p1 = (Point3D) boundaryPoints.elementAt(i); for (int j = i + 1; j < boundaryPoints.size(); j++) { p2 = (Point3D) boundaryPoints.elementAt(j); if (p1.isNeighbour(p2)) { neighbours.add((Point3D) boundaryPoints.elementAt(j)); } } neighbours_vector.add(i, neighbours); } // allright, we have a vector points with // all boundary points // we have a vector neighbours_vector // with a vector of all neighbours of points[i] // position neighbours_vector[i] Vector tmp, tmp2; @SuppressWarnings("unused") boolean similar; int i, j, k; // go through the entired list of boundary points. // the observed point shall be p1 for (i = 0; i < boundaryPoints.size(); i++) { p1 = (Point3D) boundaryPoints.elementAt(i); // go through the list of neighbours of p1 tmp = (Vector) neighbours_vector.elementAt(i); for (j = 0; j < tmp.size(); j++) { p2 = (Point3D) tmp.elementAt(j); // go through the list of neighbours of each // neighbour p2 and check if it is neighbour // of p1, too // if it is a neighbour then create a new // triangle tmp2 = (Vector) neighbours_vector.elementAt(boundaryPoints.indexOf(p2)); for (k = 0; k < tmp2.size(); k++) { if (p1.isNeighbour((Point3D) tmp2.elementAt(k))) { t.add(new Triangle(p1, p2, (Point3D) tmp2.elementAt(k))); } } } } System.out.println("Triangulation into triangles ended."); } }