/*
* 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 java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;
import org.apache.log4j.Logger;
/**
* Each section consists of a set of segments, which are sequentionally connected.
*
* @author Jens Eberhard
* @author Alexander Wanner
* @author Sergei Wolf
*/
public class Section implements Serializable {
static final long serialVersionUID = -7031941169184524614L;
/** use to log messages */
private final static Logger logger = Logger.getLogger(Section.class.getName());
private int id = -1;
private static int secCounter;
/** Segments this section consists of.*/
protected final List<Segment> segmentList;
/** Link to the parent section this section is branching of. (NULL if a root section)*/
protected SectionLink parentalLink;
/** Link to the both branches of this section. (NULL, if a final section) */
protected SectionLink childrenLink;
protected String name;
public enum SectionType {
BASAL(0), APICAL(1), OBLIQUE(2), MYELINIZED(3), NOT_MYELINIZED(4), UNDEFINED(5), SOMA(6);
private int secNum;
private SectionType(int secNum) {
this.secNum = secNum;
}
public int getSecNum() {
return secNum;
}
}
protected SectionType secType;
public SectionType getSectionType() {
return secType;
}
public void setSectionType(SectionType type) {
this.secType = type;
}
public Section() {
segmentList = new ArrayList<Segment>();
setId(secCounter++);
}
public Section(Section source) {
id = source.id;
name = source.name;
childrenLink = source.childrenLink;
parentalLink = source.parentalLink;
segmentList = source.segmentList;
}
/**
* Constructor to create a line section with a given number of compartments, endradii, and endpoints.
*/
public Section(float startRadius, Point3f startPoint, float endRadius, Point3f endPoint, int numSegments) {
segmentList = new ArrayList<Segment>();
setId(secCounter++);
float oldRad = startRadius;
Point3f oldEnd = new Point3f(startPoint);
Point3f newEnd = new Point3f();
for (int i = 0; i < numSegments; ++i) {
float position = (i + 1.0f) / (float) numSegments;
float newRad = (1 - position) * startRadius + position * endRadius;
newEnd.x = (1 - position) * startPoint.x + position * endPoint.x;
newEnd.y = (1 - position) * startPoint.y + position * endPoint.y;
newEnd.z = (1 - position) * startPoint.z + position * endPoint.z;
Segment segment = new Segment();
segment.setSegment(oldEnd, newEnd, oldRad, newRad);
segmentList.add(segment);
oldEnd = new Point3f(newEnd);
oldRad = newRad;
}
}
public static int getSecCounter() {
return Section.secCounter;
}
public static void resetSecCounter() {
Section.secCounter = 0;
logger.info("reset section counter:" + Section.secCounter);
}
/**
* Get the value of name
*
* @return the value of name
*/
public String getName() {
return name;
}
/**
* Set the value of name
*
* @param name new value of name
*/
public void setName(String name) {
this.name = name;
}
public List<Segment> getSegments() {
return segmentList;
}
public SectionLink getParentalLink() {
return parentalLink;
}
public SectionLink getChildrenLink() {
return childrenLink;
}
public void setParentalLink(SectionLink parental) {
parentalLink = parental;
}
public void setChildrenLink(SectionLink children) {
childrenLink = children;
}
public int getId() {
if (id < 0) {
id = secCounter;
}
return id;
}
public final void setId(int id) {
this.id = id;
}
/**
* Get polygonal composed length of this section.
*
* @return polygonal composed length of this section.
*/
public float getLength() {
float ret = 0.0f;
for (int i = 0; i < segmentList.size(); ++i) {
ret += segmentList.get(i).getLength();
}
return ret;
}
public Iterator getIterator() {
return new Iterator(this);
}
/**
* Get relative coordinate of the childs beginning
* along the parent section. Implicitely the "beginning" is
* the 0th end of the child
* @param child
* @return 0.0 ... 1.0, -1.0 if child is not a real child
*/
public float getFractAlongParentForChild(Section child) {
Set<Section> children;
if (getChildrenLink() == null) {
children = new HashSet<Section>();
children.add(child);
} else {
children = getChildrenLink().getChildren();
}
for (Section ch : children) {
if (ch == child) {
Segment firstChildSegment = child.getSegments().get(0);
Point3f sstart = firstChildSegment.getStart();
List<Segment> parentSecSegments = getSegments();
if (parentSecSegments.size() > 0) {
Point3f parentStart = parentSecSegments.get(0).getStart();
Point3f parentEnd = parentSecSegments.get(parentSecSegments.size() - 1).getEnd();
Vector3f tmp = new Vector3f();
tmp.sub(sstart, parentStart);
float diff = tmp.lengthSquared();
tmp.sub(sstart, parentEnd);
float diff2 = tmp.lengthSquared();
if (diff > diff2) {
return 1.0f;
} else {
return 0.0f;
}
} else {
return -1.0f;
}
}
}
return -1.0f;
}
public void printSection() {
for (Segment segment : segmentList) {
logger.info(segment.toString());
}
}
public class Iterator implements Serializable, java.util.Iterator<Section> {
private static final long serialVersionUID = -2311930069184524614L;
//private LinkedList<Pair<Section, SectionAdress>> processingQueue = new LinkedList<Pair<Section, SectionAdress>>();
//private final List<Section> processing;
private final Set<Section> processing;
/*private SectionAdress sectionAdress = new SectionAdress("0", 0);
private SectionAdress parentSectionAdress = new SectionAdress("0", 0);*/
/** Root of the subtree to iterate over. */
private Section top;
/** Next section returned by next(). */
private Section next;
/** Flag is set if next lies lower. */
private boolean down;
/** Flag to show a subtree not completly iterated yet. */
private boolean unret_st;
public Iterator(Section section) {
next = section;
top = section;
processing = new HashSet<Section>();
processing.add(section);
down = true;
}
@Override
public boolean hasNext() {
//logger.debug("hastNext processQueue.size: " + processingQueue.size());
return !processing.isEmpty();
}
public Section get(int secId) {
Section currSec = next();
int currSecId = currSec.getId();
while (currSecId != secId) {
currSec = next();
if (currSec == null) {
return null;
} else {
currSecId = currSec.getId();
}
}
return currSec;
}
@Override
public Section next() {
java.util.Iterator<Section> it = processing.iterator();
Section sec = it.next();
it.remove();
if (sec.getChildrenLink() != null) {
SectionLink sectionLink = sec.getChildrenLink();
processing.addAll(sectionLink.getChildren());
}
return sec;
}
/*public SectionAdress getParentSectionAdress() {
return parentSectionAdress;
}
public SectionAdress getSectionAdress() {
return sectionAdress;
}*/
/*
public Section getNext() {
Section ret = next;
if (ret == null) {
return null;
}
if (ret == top && !down) {
ret = null;
}
if (next != null) {
Section n1 = next;
if (down) {
SectionLink childrenLink = next.getChildrenLink();
boolean branches = false;
if (childrenLink != null) {
Section branch0 = childrenLink.getBranch0();
Section branch1 = childrenLink.getBranch1();
if (branch0 != null || branch1 != null) {
if (branch0 != null) {
next = branch0;
branches = true;
} else {
next = branch1;
branches = true;
}
}
}
if (!branches) {
SectionLink parentalLink = next.getParentalLink();
Section parentSec = null;
if (parentalLink != null) {
parentSec = parentalLink.getParental();
if (parentSec != null) {
SectionLink parentSecChildrenLink = parentSec.getChildrenLink();
n1 = parentSecChildrenLink.getBranch1();
} else {
n1 = null;
}
} else {
n1 = null;
}
if (next == top) {
next = null;
} else if (n1 != next) {
if (n1 == null) {
next = parentalLink.getParental();
down = false;
getNext();
} else {
next = n1;
}
} else {
next = parentalLink.getParental();
down = false;
getNext();
}
}
} else {
if (next == top) {
next = null;
} else {
SectionLink parentalLink = next.getParentalLink();
Section branch1 = parentalLink.getParental().getChildrenLink().getBranch1();
if (branch1 != null) {
if (branch1 != next) {
n1 = branch1;
}
}
if (n1 == next) {
next = parentalLink.getParental();
getNext();
} else {
down = true;
next = n1;
}
}
}
}
return ret;
}
*
*/
@Override
public void remove() {
throw new UnsupportedOperationException("Not supported yet.");
}
/*public Section nextOld() {
if (processingQueue.size() > 0) {
Pair<Section, SectionAdress> pair = processingQueue.getLast();
Section section = pair.first;
SectionAdress sectionAdressLoc = pair.second;
processingQueue.removeLast();
if (section.getChildrenLink() != null) {
logger.debug("section has children links: " + section.getSectionName());
SectionLink sectionLink = (SectionLink) section.getChildrenLink();
int numSecChildren = sectionLink.childrenSet.size();
java.util.Iterator<Section> it = sectionLink.childrenSet.iterator();
int counter = 0;
while (it.hasNext()) {
Section secChild = it.next();
SectionAdress newSectionAdress;
String branch = sectionAdressLoc.branch;
int localID = sectionAdressLoc.localID;
if (numSecChildren == 1) {
localID++;
} else {
localID = 0;
branch = branch + counter;
}
newSectionAdress = new SectionAdress(branch, localID, sectionAdressLoc);
processingQueue.addFirst(new Pair<Section, SectionAdress>(secChild, newSectionAdress));
logger.debug("put this section in the queue: " + secChild.getSectionName());
counter++;
}*/
/*for (int i = 0; i < numSecChildren; i++) {
Section secChild = sectionLink.childrenSet.get(i);
SectionAdress newSectionAdress;
String branch = sectionAdressLoc.branch;
int localID = sectionAdressLoc.localID;
if (numSecChildren == 1) {
localID++;
} else {
localID = 0;
branch = branch + i;
}
newSectionAdress = new SectionAdress(branch, localID, sectionAdressLoc);
processingQueue.addFirst(new Pair<Section, SectionAdress>(secChild, newSectionAdress));
logger.debug("put this section in the queue: " + secChild.getSectionName());
}*/
/*} else {
logger.debug("section has no children links: " + section.getSectionName());
}
this.sectionAdress = sectionAdressLoc;
this.parentSectionAdress = sectionAdressLoc.parentAdress;
return section;
}
return null;
}*/
/*public class SectionAdress {
// path of branchings
public String branch = "0";
// local id of a unbranched part
public int localID = 0;
public SectionAdress parentAdress = null;
public SectionAdress(String branch, int localID) {
super();
this.branch = branch;
this.localID = localID;
}
public SectionAdress(String branch, int localID,
SectionAdress parentAdress) {
super();
this.branch = branch;
this.localID = localID;
this.parentAdress = parentAdress;
}
@Override
public String toString() {
return branch + "_" + localID;
}
}*/
}
}