/* * Copyright (C) 2010-2014 Andreas Maier * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */ package edu.stanford.rsl.conrad.geometry.splines; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import com.jogamp.opencl.CLContext; import com.jogamp.opencl.CLDevice; import edu.stanford.rsl.conrad.geometry.AbstractCurve; import edu.stanford.rsl.conrad.geometry.AbstractShape; import edu.stanford.rsl.conrad.geometry.AbstractSurface; import edu.stanford.rsl.conrad.geometry.General; import edu.stanford.rsl.conrad.geometry.motion.MotionField; import edu.stanford.rsl.conrad.geometry.motion.OpenCLParzenWindowMotionField; import edu.stanford.rsl.conrad.geometry.motion.ParzenWindowMotionField; import edu.stanford.rsl.conrad.geometry.shapes.compound.CompoundShape; import edu.stanford.rsl.conrad.geometry.shapes.simple.PointND; import edu.stanford.rsl.conrad.geometry.shapes.simple.Triangle; import edu.stanford.rsl.conrad.geometry.transforms.Transform; import edu.stanford.rsl.conrad.numerics.SimpleVector; import edu.stanford.rsl.conrad.opencl.OpenCLUtil; import edu.stanford.rsl.conrad.utils.Configuration; import edu.stanford.rsl.conrad.utils.RegKeys; import edu.stanford.rsl.conrad.utils.TessellationUtil; public class TimeVariantSurfaceBSpline extends AbstractSurface { /** * */ private static int tesselationCount = 0; private static int tesselationCount1 = 0; protected ArrayList<SurfaceBSpline> timeVariantShapes; private String title; private static final long serialVersionUID = 6323388850451960550L; protected BSpline timeSpline; protected int tPoints; protected boolean clockwise; public boolean isClockwise(){ return clockwise; } public TimeVariantSurfaceBSpline(ArrayList<SurfaceBSpline> splines){ timeVariantShapes = splines; init(); } public TimeVariantSurfaceBSpline(SurfaceBSpline timeInvariant, MotionField motion, int timePoints, boolean addInitial){ timeVariantShapes = new ArrayList<SurfaceBSpline>(); ArrayList<PointND> initialPoints = timeInvariant.getControlPoints(); // add initial state. if (addInitial) { timeVariantShapes.add(new SurfaceUniformCubicBSpline(initialPoints, timeInvariant.getUKnots(), timeInvariant.getVKnots())); } // Time information comes from the time variant spline(s) tPoints = timePoints; ArrayList<ArrayList<PointND>> newPoints = new ArrayList<ArrayList<PointND>>(); if (motion instanceof ParzenWindowMotionField) { for (int t = 1; t < tPoints; t++){ PointND [] pointsArray = new PointND[initialPoints.size()]; initialPoints.toArray(pointsArray); ArrayList<PointND> pts = null; if (OpenCLUtil.isOpenCLConfigured()){ try { CLContext context = OpenCLUtil.getStaticContext(); CLDevice device = context.getMaxFlopsDevice(); OpenCLParzenWindowMotionField openCLMotion = new OpenCLParzenWindowMotionField((ParzenWindowMotionField)motion, context, device); pts = openCLMotion.getPositions(0, ((double)t)/(tPoints-1), pointsArray); } catch (IOException e) { // Program not found. e.printStackTrace(); } } else { pts = motion.getPositions(0, ((double)t)/(tPoints-1), pointsArray); } newPoints.add(pts); } } else { double [] times = new double [tPoints-1]; for (int t = 1; t < tPoints; t++){ newPoints.add(new ArrayList<PointND>()); times[t-1] = ((double)t)/(tPoints-1); } for (int i = 0; i < initialPoints.size(); i++){ ArrayList<PointND> pts = motion.getPositions(initialPoints.get(i), 0, times); for (int t = 1; t < tPoints; t++){ newPoints.get(t-1).add(pts.get(t-1)); } } } for (int t = 1; t < tPoints; t++) { timeVariantShapes.add(new SurfaceUniformCubicBSpline(newPoints.get(t-1), timeInvariant.getUKnots(), timeInvariant.getVKnots())); } // Set properties for timeVariantShapes for (int t = 0; t < timeVariantShapes.size(); t++) { timeVariantShapes.get(t).setTitle(timeInvariant.getTitle()); timeVariantShapes.get(t).setClockwise(timeInvariant.isClockwise()); } init(); } public TimeVariantSurfaceBSpline(TimeVariantSurfaceBSpline tvs){ super(tvs); title = (tvs.title!=null) ? new String(tvs.title) : null; tPoints = tvs.tPoints; clockwise = tvs.clockwise; if (tvs.timeVariantShapes != null){ Iterator<SurfaceBSpline> it = tvs.timeVariantShapes.iterator(); timeVariantShapes = new ArrayList<SurfaceBSpline>(); while (it.hasNext()) { SurfaceBSpline spl = it.next(); timeVariantShapes.add((spl!=null) ? (SurfaceBSpline) spl.clone() : null); } } else{ timeVariantShapes = null; } timeSpline = (tvs.timeSpline!=null) ? (BSpline)tvs.timeSpline.clone() : null; } private void init(){ max = new PointND(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE); min = new PointND(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE); for (AbstractShape spline: timeVariantShapes) { max.updateIfHigher(spline.getMax()); min.updateIfLower(spline.getMin()); } tPoints = timeVariantShapes.size(); setTitle(timeVariantShapes.get(0).getTitle()); createTimeSpline(); clockwise = timeVariantShapes.get(0).clockwise; // assumes all time steps have same orientation } private void createTimeSpline(){ SimpleVector knotVector = new SimpleVector(4+timeVariantShapes.size()); ArrayList<PointND> controlPoints = new ArrayList<PointND>(); int count = 0; for (count = 0; count < 4; count++){ knotVector.setElementValue(count, 0); controlPoints.add(new PointND(0, 0, 0)); } for (count = 4; count < timeVariantShapes.size(); count++){ knotVector.setElementValue(count, ((count - 3.0) / (timeVariantShapes.size() - 3.0))); controlPoints.add(new PointND(1, 1, 1)); } for (count = timeVariantShapes.size(); count < timeVariantShapes.size() + 4; count++){ knotVector.setElementValue(count, 1.0); } timeSpline = new UniformCubicBSpline(controlPoints, knotVector); } public int getNumberOfTimePoints(){ return tPoints; } public ArrayList<PointND> getControlPoints(int time){ return timeVariantShapes.get(time).getControlPoints(); } @Override public void applyTransform(Transform t) { for (AbstractShape spline: timeVariantShapes){ spline.applyTransform(t); } } @Override public int getDimension() { return timeVariantShapes.get(0).getDimension(); } @Override public PointND evaluate(PointND u) { return evaluate(u.get(0), u.get(1), u.get(2)); } public PointND evaluate(double u, double v, double t){ double [] p = new double [timeVariantShapes.get(0).getControlPoints().get(0).getDimension()]; double internal = ((t * timeSpline.getKnots().length) -3.0); int numPts = timeSpline.getControlPoints().size(); double step = internal- Math.floor(internal); //System.out.println(u + " " + internal); double [] weights = UniformCubicBSpline.getWeights(step); for (int i=0;i<4;i++){ double [] loc = (internal+i < 0)? ((SurfaceBSpline)timeVariantShapes.get(0)).evaluate(u, v).getCoordinates(): (internal+i>=numPts)? ((SurfaceBSpline)timeVariantShapes.get(numPts-1)).evaluate(u, v).getCoordinates() : ((SurfaceBSpline)timeVariantShapes.get((int) (internal+i))).evaluate(u, v).getCoordinates(); for (int j = 0; j < loc.length; j++){ p[j] += (loc[j] * weights[i]); //p[j] = loc[j]; } } return new PointND(p); } @Deprecated public PointND evaluateFull(double u, double v, double t){ SimpleVector point = new SimpleVector(getDimension()); for (int i = 0; i < tPoints; i++){ //System.out.println("Upoints: " + uPoints + " " + i); double weight = timeSpline.getWeight(t, i); point.add(((SurfaceBSpline)timeVariantShapes.get(i)).evaluate(u, v).getAbstractVector().multipliedBy(weight)); } PointND revan = new PointND(point); return revan; } public PointND[] getRasterPoints(double samplingU, double samplingV, double time){ PointND [] pts = new PointND[((int)samplingU) * ((int)samplingV)]; for(double i =0 ; i < samplingU; i++){ for (double j = 0; j < samplingV; j++){ PointND p = evaluate(i/samplingU, j/ samplingV, time); pts[(int)(i*samplingV+j)] = p; } } return pts; } public AbstractShape tessellateMesh(double samplingU, double samplingV, double time){ PointND [] pts = getRasterPoints(samplingU, samplingV, time); boolean write = false; BufferedWriter bwpoint = null; String filename = Configuration.getGlobalConfiguration().getRegistry().get(RegKeys.XCAT_WRITE_MESH); if (filename != null) { String substring = Configuration.getGlobalConfiguration().getRegistry().get(RegKeys.XCAT_WRITE_MESH_SURFACE_SUBSTRING); if (substring != null){ write = getTitle().contains(substring); } if (write){ String splineName = getTitle().replace('*', '-'); try { //bwpoint = new BufferedWriter(new FileWriter(filename + "_" + splineName + "_" + time + ".points.txt")); bwpoint = new BufferedWriter(new FileWriter(filename + "_" + splineName + "_" + tesselationCount + ".points.txt")); tesselationCount++; bwpoint.write(splineName+"\n"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); throw new RuntimeException(e); } } } CompoundShape superShape = new CompoundShape(); ArrayList<PointND> lastSlice = new ArrayList<PointND>(); ArrayList<PointND> firstSlice = new ArrayList<PointND>(); for(double i =1 ; i < samplingU; i++){ CompoundShape mesh = new CompoundShape(); double lasti = i - 1; if (lasti < 0) lasti = samplingU - 1; for (double j = 0; j < samplingV; j++){ double lastj = j - 1; if (lastj < 0) lastj = samplingV - 1; if (i == samplingU-1) lastSlice.add(pts[(int)(i*samplingV+j)]); if (i == 1) firstSlice.add(pts[(int)((i-1)*samplingV+j)]); try{ Triangle t1 = new Triangle(pts[(int)(lasti*samplingV+lastj)] , pts[(int)(i*samplingV+lastj)] , pts[(int)(lasti*samplingV+j)]); t1.setName(i+"x"+j+"u"); if (write){ PointND pt = pts[(int)(lasti*samplingV+lastj)]; bwpoint.write(lasti+"x"+lastj+"\t"+i+"x"+j+"u\t"+pt.get(0)+"\t"+pt.get(1)+"\t"+pt.get(2)+"\n"); pt = pts[(int)(i*samplingV+lastj)]; bwpoint.write(i+"x"+lastj+"\t"+i+"x"+j+"u\t"+pt.get(0)+"\t"+pt.get(1)+"\t"+pt.get(2)+"\n"); pt = pts[(int)(lasti*samplingV+j)]; bwpoint.write(lasti+"x"+j+"\t"+i+"x"+j+"u\t"+pt.get(0)+"\t"+pt.get(1)+"\t"+pt.get(2)+"\n"); } mesh.add(t1); } catch (Exception e){ if (!e.getLocalizedMessage().contains("direction vector")){ System.out.println(e.getLocalizedMessage() +" "+ i + " " + j + " " + lasti + " " + lastj); } } try{ Triangle t2 = new Triangle(pts[(int)(i*samplingV+lastj)] , pts[(int)(lasti*samplingV+j)] , pts[(int)(i*samplingV+j)]); t2.setName(i+"x"+j+"l"); if (write){ PointND pt = pts[(int)(i*samplingV+lastj)]; bwpoint.write(i+"x"+lastj+"\t"+i+"x"+j+"l\t"+pt.get(0)+"\t"+pt.get(1)+"\t"+pt.get(2)+"\n"); pt = pts[(int)(lasti*samplingV+j)]; bwpoint.write(lasti+"x"+j+"\t"+i+"x"+j+"l\t"+pt.get(0)+"\t"+pt.get(1)+"\t"+pt.get(2)+"\n"); pt = pts[(int)(i*samplingV+j)]; bwpoint.write(i+"x"+j+"\t"+i+"x"+j+"l\t"+pt.get(0)+"\t"+pt.get(1)+"\t"+pt.get(2)+"\n"); } mesh.add(t2); } catch (Exception e){ if (!e.getLocalizedMessage().contains("direction vector")){ System.out.println(e.getLocalizedMessage() +" "+ i + " " + j + " " + lasti + " " + lastj); } } } superShape.add(mesh); } superShape.addAll(General.createTrianglesFromPlanarPointSet(lastSlice, "firstSlice", bwpoint)); superShape.addAll(General.createTrianglesFromPlanarPointSet(firstSlice, "lastSlice", bwpoint)); if (write){ try { bwpoint.flush(); bwpoint.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //System.out.println("Triangles: " + superShape + " " + superShape.getInternalDimension() + " " + superShape.size()); superShape.setName(getTitle()); if (write){ try { String splineName = getTitle().replace('*', '-'); //BufferedWriter bw = new BufferedWriter(new FileWriter(filename + "_" + splineName + "_" + time + ".txt")); BufferedWriter bw = new BufferedWriter(new FileWriter(filename + "_" + splineName + "_" + tesselationCount1 + ".txt")); tesselationCount1++; bw.write(splineName+"\n"); for (int i = 0; i < superShape.getInternalDimension(); i++){ AbstractShape subShape = superShape.get(i); if (subShape instanceof CompoundShape) { CompoundShape cmpShape = (CompoundShape) subShape; for (int j=0;j <cmpShape.size(); j++){ Triangle tri = (Triangle) cmpShape.get(j); bw.write(tri.toString()+"\n"); } } else { bw.write(subShape.toString()+"\n"); } } bw.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return superShape; } @Override public int getInternalDimension() { return 3; } @Override public PointND[] getRasterPoints(int number) { // TODO Auto-generated method stub return null; } public PointND[] getRasterPoints(int number, double time){ int root = (int) Math.sqrt(number); PointND [] points = new PointND[root*root]; for (double u =0; u < root; u++){ for (double v = 0; v < root; v++){ points[(int)((v*root)+u)] = evaluate(u/root, v/root, time); } } return points; } @Override public ArrayList<PointND> intersect(AbstractCurve other) { throw new RuntimeException("Not yet implemented"); } /** * @param title the title to set */ public void setTitle(String title) { this.title = title; } /** * @return the title */ public String getTitle() { return title; } @Override public boolean isBounded() { return true; } /** * Returns a binary representation of a time variant surface spline: * <pre> * type * total size in float values * # of surface splines * ID * timeSpline * surfaceSplines * </pre> * @return the binary representation for use with OpenCL */ public float[] getBinaryRepresentation() { float type = BSpline.SPLINE3DTO3D; float tPoints = this.tPoints; float ID = BSpline.getID(title); float [] timeSpline = this.timeSpline.getBinaryRepresentation(); float [][] surfaceSplines = new float [this.tPoints][]; int timeVariantsLength = 0; for (int i = 0; i < this.tPoints; i++){ surfaceSplines[i] = this.timeVariantShapes.get(i).getBinaryRepresentation(); timeVariantsLength += surfaceSplines[i].length; } int totalsize = 4 + timeSpline.length + timeVariantsLength; float [] binary = new float [totalsize]; binary [0] = type; binary [1] = totalsize; binary [2] = ID; binary [3] = tPoints; int index = 4; for (int i = 0; i < timeSpline.length; i++){ binary[index] = timeSpline[i]; index++; } for (int i=0; i<surfaceSplines.length; i++){ for (int j = 0; j< surfaceSplines[i].length; j++){ binary[index] = surfaceSplines[i][j]; index ++; } } return binary; } public ArrayList<SurfaceBSpline> getSplines() { return timeVariantShapes; } @Override public PointND evaluate(double u, double v) { return evaluate(u, v, 0); } @Override public AbstractShape tessellate(double accuracy) { return tessellateMesh(TessellationUtil.getSamplingU(this), TessellationUtil.getSamplingV(this), 0); } @Override public AbstractShape clone() { return new TimeVariantSurfaceBSpline(this); } }