package edu.stanford.rsl.conrad.phantom.xcat;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import edu.stanford.rsl.conrad.geometry.AbstractShape;
import edu.stanford.rsl.conrad.geometry.AbstractSurface;
import edu.stanford.rsl.conrad.geometry.motion.MotionField;
import edu.stanford.rsl.conrad.geometry.motion.PointBasedMotionField;
import edu.stanford.rsl.conrad.geometry.motion.timewarp.IdentityTimeWarper;
import edu.stanford.rsl.conrad.geometry.shapes.simple.PointND;
import edu.stanford.rsl.conrad.geometry.splines.SurfaceBSpline;
import edu.stanford.rsl.conrad.geometry.splines.TimeVariantSurfaceBSpline;
import edu.stanford.rsl.conrad.parallel.ParallelThreadExecutor;
import edu.stanford.rsl.conrad.rendering.PrioritizableScene;
import edu.stanford.rsl.conrad.utils.CONRAD;
/**
* Simple scene for XCat to display the whole body. This scene does not define any motion.
*
* @author akmaier
*
*/
public class WholeBodyScene extends XCatScene {
/**
*
*/
private static final long serialVersionUID = 7514545759333848517L;
protected boolean autoResize = false;
public WholeBodyScene (){
warper = new IdentityTimeWarper();
}
@Override
public void configure() throws Exception{
setName("Whole Body Scene");
init();
createPhysicalObjects();
}
public PrioritizableScene tessellateScene(double time){
// remove previous state scene objects.
PrioritizableScene scene = new PrioritizableScene();
ArrayList<AbstractSurface> list = new ArrayList<AbstractSurface>();
list.addAll(splines);
list.addAll(variants);
int numberOfThreads = Math.min(CONRAD.getNumberOfThreads(),list.size());
TessellationThread[] threads = new TessellationThread[numberOfThreads];
Iterator<?> iter = Collections.synchronizedList(list).iterator();
for (int splineNum = 0; splineNum < numberOfThreads; splineNum++) {
threads[splineNum] = new TessellationThread(iter, warper.warpTime(time));
}
ParallelThreadExecutor executor = new ParallelThreadExecutor(threads);
try {
executor.execute();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int splineNum = 0; splineNum < numberOfThreads; splineNum++) {
for (AbstractShape s: threads[splineNum].getObjects()) {
add(scene, s, s.getName());
}
}
return scene;
}
/**
* Determines the bounds of the scene.
*/
protected void updateSceneLimits(){
max = new PointND(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE);
min = new PointND(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
int splineNum = splines.size();
for (int i=splineNum-1; i >= 0; i--){
if ((getSplineNameMaterialNameLUT().get(splines.get(i).getTitle()) != null) &&
(getSplinePriorityLUT().get(splines.get(i).getTitle()) != null)) {
max.updateIfHigher(splines.get(i).getMax());
min.updateIfLower(splines.get(i).getMin());
} else {
splines.remove(i);
}
}
}
/**
* Determines the bounds of the scene.
*/
protected void init(){
init(true);
}
/**
* Determines the bounds of the scene.
*/
protected void init(boolean keepIntersectingSplines){
splines = readSplines();
if (max == null){
updateSceneLimits();
}
// remove splines outside the volume of interest using z axis
int splineNum = splines.size();
if (keepIntersectingSplines) {
for (int i=splineNum-1; i >= 0; i--){
if (splines.get(i).getMax().get(2)
< min.get(2)){// below VOI
splines.remove(i);
} else {
if (splines.get(i).getMin().get(2) > max.get(2)) { // above VOI
splines.remove(i);
}
}
}
}
else{
// remove splines outside the volume of interest using z axis
for (int i=splineNum-1; i >= 0; i--){
if (splines.get(i).getMax().get(2)
> max.get(2)){// below VOI
splines.remove(i);
} else {
if (splines.get(i).getMin().get(2) < min.get(2)) { // above VOI
splines.remove(i);
}
}
}
}
}
/**
* Reads XCat from file.
* @return a list of splines
*/
public ArrayList<SurfaceBSpline> readSplines(){
try {
String filename = "mtorso";
if (!maleGender) {
filename = "ftorso";
}
return SurfaceBSpline.readSplinesFromFile(XCatDirectory + "/"+ filename + ".nrb");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
/**
* Creates a motion field from the scene motion plus a sequence of points in time.
* @param numberOfBSplineTimePoints
* @param additionalMotion
* @param context
* @return the motion field
*/
public MotionField getSceneMotion(int numberOfBSplineTimePoints, ArrayList<ArrayList<PointND>> additionalMotion, int context){
for (TimeVariantSurfaceBSpline tSpline:variants){
for (int t=0; t<numberOfBSplineTimePoints; t++){
additionalMotion.get(t).addAll(tSpline.getControlPoints(t));
}
}
PointND[][] array = new PointND[additionalMotion.size()][additionalMotion.get(0).size()];
for (int t = 0; t < additionalMotion.size(); t++){
array[t] = additionalMotion.get(t).toArray(array[t]);
}
MotionField motion = new PointBasedMotionField(array, context);
return motion;
}
/**
* Creates a motion field from a sequence of points in time.
* @param numberOfBSplineTimePoints
* @param additionalMotion
* @param context
* @return the motion field
*/
public MotionField getCompoundMotion(int numberOfBSplineTimePoints, ArrayList<ArrayList<PointND>> additionalMotion, int context){
PointND[][] array = new PointND[additionalMotion.size()][additionalMotion.get(0).size()];
for (int t = 0; t < additionalMotion.size(); t++){
array[t] = additionalMotion.get(t).toArray(array[t]);
}
MotionField motion = new PointBasedMotionField(array, context);
return motion;
}
@Override
public PointND getPosition(PointND initialPosition, double initialTime,
double time) {
return initialPosition;
}
@Override
public ArrayList<PointND> getPositions(PointND initialPosition,
double initialTime, double... times) {
ArrayList<PointND> newList = new ArrayList<PointND>();
for (int i = 0; i<times.length; i++){
newList.add(initialPosition);
}
return newList;
}
@Override
public String getName() {
return "XCat Whole Body";
}
@Override
public String getBibtexCitation() {
return "@article{Segars08-RCS,\n" +
" author={Segars WP, Mahesh M, Beck TJ, Frey EC, Tsui BMW},\n" +
" title={Realistic CT simulation using the 4D XCAT phantom},\n" +
" journal={Med. Phys.},\n" +
" volume={35},\n" +
" pages={3800-3808},\n" +
" year={2008}\n" +
"}";
}
@Override
public String getMedlineCitation() {
return "Segars WP, Mahesh M, Beck TJ, Frey EC, Tsui BMW. Realistic CT simulation using the 4D XCAT phantom. Med. Phys. 35:3800-3808 (2008);";
}
@Override
public float[] getBinaryRepresentation() {
// TODO Auto-generated method stub
return null;
}
}
/*
* Copyright (C) 2010-2014 Andreas Maier
* CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
*/