TrackCollection.java
package com.github.celldynamics.quimp.plugin.protanalysis;
import java.awt.Point;
import java.awt.Polygon;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
/**
* Represent collection of tracks.
*
* @author p.baniukiewicz
* @see Track
*/
public class TrackCollection {
/**
* Collection of pairs of tracks. Every pair originates from the same starting
* point. First element is backward tracks, second forward. Tracks can be empty
* but never null. Every track has different id.
*/
private ArrayList<Pair<Track, Track>> bf;
/**
* Indicates whether Track stored in this collection have initial point on first
* entry.
*/
private boolean isInitialPointIncluded;
/**
* Check if initial point is included in tracking.
*
* @return the isInitialPointIncluded
*/
public boolean isInitialPointIncluded() {
return isInitialPointIncluded;
}
private int nextId = 0;
/**
* Instantiates a new track collection.
*
* @param isInitialPointIncluded the is initial point included
*/
public TrackCollection(boolean isInitialPointIncluded) {
bf = new ArrayList<>();
this.isInitialPointIncluded = isInitialPointIncluded;
}
/**
* Add pair of tracks to collection backwardTrack,forwardTrack.
*
* @param backward backward track
* @param forward forward track
* @see #addPair(List, List)
*/
public void addPair(Polygon backward, Polygon forward) {
Track tmpB = new Track(nextId++, null);
for (int i = 0; i < backward.npoints; i++) {
tmpB.add(new Point(backward.xpoints[i], backward.ypoints[i]));
}
Track tmpF = new Track(nextId++, null);
for (int i = 0; i < forward.npoints; i++) {
tmpF.add(new Point(forward.xpoints[i], forward.ypoints[i]));
}
bf.add(new ImmutablePair<Track, Track>(tmpB, tmpF));
}
/**
* Add pair of tracks to collection.
*
* @param backward backward track points
* @param forward forward track points
* @see #addPair(Polygon, Polygon)
*/
public void addPair(List<Point> backward, List<Point> forward) {
Track b = new Track(backward, nextId++, null);
b.type = Track.TrackType.BACKWARD;
Track f = new Track(forward, nextId++, null);
f.type = Track.TrackType.FORWARD;
bf.add(new ImmutablePair<Track, Track>(b, f));
}
/**
* Get iterator over pairs of tracks (related to one starting point).
*
* @return iterator
*/
public Iterator<Pair<Track, Track>> iterator() {
return bf.iterator();
}
/**
* Get iterator over all tracks in collection.
*
* @return iterator
*/
public Iterator<Track> iteratorTrack() {
List<Track> ret = new ArrayList<>();
for (Pair<Track, Track> p : bf) {
ret.add(p.getLeft());
ret.add(p.getRight());
}
return ret.iterator();
}
/**
* Get unmodifiable list of all tracks.
*
* @return the bf list of all tracks (forward,backward)
*/
public List<Pair<Track, Track>> getBf() {
return Collections.unmodifiableList(bf);
}
/**
* Save tracks to csv file.
*
* <p>
* Format of the file is:
*
* <pre>
* Point 000 backward;[frame],10.0,11.0
* Point 000 backward;[index],110.0,111.0
* Point 000 forward;[frame],0.0,1.0,2.0
* Point 000 forward;[index],100.0,101.0,102.0
* Point 001 backward;[frame],30.0,31.0,32.0,33.0,34.0
* Point 001 backward;[index],130.0,131.0,132.0,133.0,134.0
* Point 001 forward;[frame],20.0,21.0,22.0,23.0
* Point 001 forward;[index],120.0,121.0,122.0,123.0
* </pre>
*
* <p>
* First columns is legend, next columns are indexes of rows and columns in maps
* returned from Q-Analysis. To obtain screen coordinates one can use xCoord and
* yCorrd maps. Tracks for each point are saved alternately in the order
* Backward - Forward. Each track occupies two rows for frame and outline
* position coordinates.
*
* @param writer where to save
* @throws IOException on error
*/
public void saveTracks(Writer writer) throws IOException {
Iterator<Pair<Track, Track>> iter = iterator();
int pointno = 0;
// description
writer.write("# Each tracked point has two tracks connected to it: backward and forward\n");
writer.write("# Each track is defined by two coordinates: frame nummber and outline position\n");
writer.write("# Numbers are indexes of maQP arrays taht can be extracted from QCONF\n");
writer.write("# by FormatConverter.\n");
while (iter.hasNext()) {
Pair<Track, Track> track = iter.next();
StringBuilder sb = new StringBuilder();
sb.append(String.format("Point %03d backward;[frame]", pointno));
sb.append(',');
for (Point p : track.getLeft()) {
sb.append(p.x);
sb.append(',');
}
sb.deleteCharAt(sb.length() - 1);
sb.append('\n');
sb.append(String.format("Point %03d backward;[index]", pointno));
sb.append(',');
for (Point p : track.getLeft()) {
sb.append(p.y);
sb.append(',');
}
sb.deleteCharAt(sb.length() - 1);
sb.append('\n');
sb.append(String.format("Point %03d forward;[frame]", pointno));
sb.append(',');
for (Point p : track.getRight()) {
sb.append(p.x);
sb.append(',');
}
sb.deleteCharAt(sb.length() - 1);
sb.append('\n');
sb.append(String.format("Point %03d forward;[index]", pointno));
sb.append(',');
for (Point p : track.getRight()) {
sb.append(p.y);
sb.append(',');
}
sb.deleteCharAt(sb.length() - 1);
sb.append('\n');
writer.write(sb.toString());
pointno++;
}
}
}