/* * 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 * */ package org.neugen.datastructures; import java.io.Serializable; import javax.vecmath.Point3f; import javax.vecmath.Vector3f; import org.apache.log4j.Logger; /** * Contains the basic class for the construction of a neuron. * Segment which is the basic compartment for the axon and dendrites of a neuron. * The compartment is a frustum in general, but it can be used as a cylinder for * the simplest case. * * @author Jens Eberhard * @author Simone Eberhard * @author Alexander Wanner * @author Sergei Wolf */ public class Segment implements Serializable { private static final long serialVersionUID = -7611946473283033478L; /** use to log messages */ private static final Logger logger = Logger.getLogger(Segment.class.getName()); /** Start of segment. */ protected Point3f startPoint; /** End of segment. */ protected Point3f endPoint; /** Vector from the star in the direction of the end. */ protected Vector3f direction; /** Length of segment. */ protected float length; /** Radius at start of segment. */ protected float startRadius; /** Radius at end of segment. */ protected float endRadius; /** Id of segment. */ protected int id = -1; /** Counter for all segments. */ protected static int segmentCounter; /** Reference to parent segment. */ protected Segment parent; protected int parentId; /** Reference to child segment. */ protected Segment child; /** Name given to Segment, unique within a neuron. */ protected String name; /** true exactly if this segment carries a synapse. */ protected boolean synapse; /** true exactly if this segment carries a non_functional synapse. */ protected boolean nfSynapse; /** geometric distance of segment to the soma. */ protected float distToSoma; protected boolean test; /** Constructor. It initializes only the spatial dimension. */ public Segment() { nfSynapse = false; length = 0.0f; startRadius = -1.0f; endRadius = 0.0f; setId(segmentCounter++); } public Point3f getCenter() { Point3f center = new Point3f(); center.add(startPoint, endPoint); center.scale(0.5f); return center; } public static void resetSegCounter() { Segment.segmentCounter = 0; logger.info("segment counter is:" + Segment.segmentCounter); } /** * Interpolation function. * @param startRadius start radius of section * @param endRadius of section * @param n number of segments * @param interpType type of interpolation (unused). * By default linear interpolation by number. */ public static float interpolateRadii(float startRadius, float endRadius, int n, int pos, int interpType) { return startRadius - (startRadius - endRadius) / n * (pos + 1); } /** * Interpolation function for branch points. * To a given startradius, endradius, number of segments, branch point and * the ralls coefficients it calculates the radii of the * connected sections. Returns a 3D array of the radii: [radParent,radBranch1,radBranch2] * The ralls rule is radParent^rall.a=radBranch1^rall.a + radBranch^rall.a and radBranch1= radParent*rall.c * @param startRadius is the start radius of the reference string * @param endRadius is the end radius of the reference string * @param n number of segments in the reference string * @param pos is the position of the branch point, number of the segment * of main string after branch point */ public static float[] interpolateRadii(float startRadius, float endRadius, int n, int pos, float rallA, float rallC) { float[] radii = new float[3]; if (pos < 1) { radii[0] = startRadius; } if (pos > n) { radii[0] = endRadius; } else { radii[0] = interpolateRadii(startRadius, endRadius, n, pos - 1, 0); } radii[1] = rallC * radii[0]; radii[2] = radii[0] * (float) Math.pow(1 - Math.pow(rallC, rallA), 1 / rallA); return radii; } /** * Get the value of parentId * * @return the value of parentId */ public int getParentId() { return parentId; } /** * Set the value of parentId * * @param parentId new value of parentId */ public void setParentId(int parentId) { this.parentId = parentId; } /** * Return the id of segment. * * @return id of segment. */ public int getId() { if (id < 0) { id = segmentCounter; } return id; } /** * Return the distance to soma of segment. * * @return distToSoma distance to soma of segment. */ public float getDistToSoma() { return distToSoma; } /** * Set the id of the segment. * * @param id The id of segment. */ public final void setId(int segmentId) { this.id = segmentId; } /** * Get the value of child * * @return the value of child */ public Segment getChild() { return child; } /** * Set the value of child. * * @param child new value of child */ public void setChild(Segment child) { this.child = child; } /** * Get the parent of segment. * * @return parent The parent of segment. */ public Segment getParent() { return parent; } /** * Set the parent of the segment. * * @param parentSegment The parent of segment. */ public void setParent(Segment parentSegment) { this.parent = parentSegment; } /** * Get the name of the segment. * * @return name The name of segment */ public String getName() { return name; } public void setName(String segmentName) { this.name = segmentName; } /** * Set a segment. * It computes its length and direction. * * @param sstart The start of segment. * @param send The end of segment. * @param sradius The radius of segment. */ public void setSegment(Point3f sstart, Point3f send, float sradius) { setSegment(sstart, send, sradius, sradius); } /** * Set a segment. * It computes its length and direction. * * @param sstart The start of segment. * @param send The end of segment. * @param sradiusstart The radius at start. * @param sradiusend The radius at end. */ public void setSegment(Point3f sstart, Point3f send, float sradiusstart, float sradiusend) { startPoint = sstart; endPoint = send; /* if (sstart != null && send != null) { direction = new Vector3f(); direction.sub(endPoint, startPoint); length = direction.length(); direction.normalize(); } * */ startRadius = sradiusstart; endRadius = sradiusend; distToSoma = 0.0f; } /** * Set a segment. * It computes its length, direction, and its distance to the soma. * * @param cstart The start of segment. * @param cend The end of segment. * @param cradiusstart The radius at start. * @param cradiusend The radius at end. * @param soma_x The location of the soma. */ public void setSegment(Point3f cstart, Point3f cend, float cradiusstart, float cradiusend, Point3f soma_x) { startPoint = cstart; endPoint = cend; startRadius = cradiusstart; endRadius = cradiusend; direction = new Vector3f(); direction.sub(endPoint, startPoint); length = direction.length(); direction.normalize(); Vector3f tmp = new Vector3f(); tmp.add(startPoint, endPoint); tmp.scale(0.5f); tmp.sub(soma_x); distToSoma = tmp.length(); logger.debug("Segment from " + startPoint + " to " + endPoint + " \n\tstart radius " + startRadius + " end radius " + endRadius + " length " + length); } public void setStart(Point3f start) { this.startPoint = start; } /** * Get start point of segment. * * @return startPoin The start point of segment. */ public Point3f getStart() { if (startPoint == null) { if(parent != null) { startPoint = parent.getEnd(); } } return startPoint; } public void setEnd(Point3f end) { this.endPoint = end; } /** * Get end point of segment. * * @return endPoint The end point of segment. */ public Point3f getEnd() { if (endPoint == null) { if (direction != null) { Point3f ret = new Point3f(); ret.scale(length, direction); ret.add(startPoint); endPoint = ret; } else { return null; } } return endPoint; } /** * Get length of segment. * * @return length The length of segment. */ public float getLength() { if(length == 0.0f) { if(endPoint == null || startPoint == null) { logger.error("segment id(endPoint == null || startPoint == null): " + id); //throw new NullPointerException(); return 0.0f; } direction = new Vector3f(); direction.sub(endPoint, startPoint); length = direction.length(); direction.normalize(); } return length; } /** * Get start radius of segment. * * @return start The radius of segment. */ public float getStartRadius() { return startRadius; } public void setEndRadius(float endRadius) { this.endRadius = endRadius; } /** * Get end radius of segment. * * @return endRadius The end radius of segment. */ public float getEndRadius() { return endRadius; } /** * Get direction of segment. * * @return direction The direction of segment. */ public Vector3f getDirection() { if(direction == null) { direction = new Vector3f(); direction.sub(endPoint, startPoint); direction.normalize(); } return direction; } /** * Get surface area of segment. * * @return surfaceArea The surface area of segment. */ public float getSurfaceArea() { double surfaceArea = Math.PI * (startRadius + endRadius) * Math.sqrt(length * length) + (startRadius - endRadius) * (startRadius - endRadius); return (float) surfaceArea; } /** * Get volume of segment. * (volume of frustum: 1/3 PI h (r_1^2 + r_1*r_2 + r_2^2)) (simone) * * @return volumeOfSegment The volume of segment */ public float getVolume() { float volumeOfSegment = 0.0f; //volume= 1/3 PI h (r_1^2 + r_1*r_2 + r_2^2) volumeOfSegment = (1.0f / 3.0f) * (float) Math.PI * getLength() * ((startRadius * startRadius) + (startRadius * endRadius) + (endRadius * endRadius)); //volumeOfSegment = (float) (Math.PI * getLength() * startRadius * startRadius); //logger.info( "volumeOfSegment: " + volumeOfSegment ); if(test) { //logger.info("volumen dieses segments wurde schon abgefragt: " + this.id); } test = true; return volumeOfSegment; } @Override public String toString() { String ret; float sradiusstart, sradiusend; sradiusstart = getStartRadius(); sradiusend = getEndRadius(); ret = (" " + getStart().x + " " + getStart().y + " " + " " + getStart().z + " " + sradiusstart); ret += "\n"; ret += (" " + getEnd().x + " " + getEnd().y + " " + getEnd().z + " " + sradiusend); logger.info(ret); return ret; } /** * Help func. for the MorphMLReader class. * * @param x The x coordinate of the segment. * @param y The y coordinate of the segment. * @param z The z coordinate of the segment. * @param diam The diameter of the segment. */ public void setStart(String x, String y, String z, String diam) { startPoint = new Point3f(); startPoint.x = Float.parseFloat(x); startPoint.y = Float.parseFloat(y); startPoint.z = Float.parseFloat(z); startRadius = (Float.parseFloat(diam)) / 2.0f; } public void setEnd(String x, String y, String z, String diam) { endPoint = new Point3f(); endPoint.x = Float.parseFloat(x); endPoint.y = Float.parseFloat(y); endPoint.z = Float.parseFloat(z); if (startPoint == null) { startPoint = parent.getEnd(); startRadius = parent.getEndRadius(); } direction = new Vector3f(); direction.sub(endPoint, startPoint); length = direction.length(); direction.normalize(); endRadius = (Float.parseFloat(diam)) / 2.0f; } /** Call this to say this segment has a double sided synapse. */ public void has_ds_synapse(boolean input) { synapse = input; } /** * Returns true if segment has a double sided synapse. * * @return synapse The value of synapse. */ public boolean has_ds_synapse() { return synapse; } /** * Returns true if segment has a non functional synapse. * * @return nfSynapse The value of nfSynapse. */ public boolean has_nf_synapse() { return nfSynapse; } /** Call this to say this segment has a non functional synapse. */ public void has_nf_synapse(boolean input) { nfSynapse = input; } }